diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 2fc585c7c795e..57e69a0efa95e 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -988,7 +988,7 @@ pub fn wants_msvc_seh(sess: &Session) -> bool { } pub fn avoid_invoke(bcx: Block) -> bool { - bcx.sess().no_landing_pads() || bcx.lpad.borrow().is_some() + bcx.sess().no_landing_pads() || bcx.lpad().is_some() } pub fn need_invoke(bcx: Block) -> bool { @@ -1616,6 +1616,7 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, param_substs: param_substs, span: sp, block_arena: block_arena, + lpad_arena: TypedArena::new(), ccx: ccx, debug_context: debug_context, scopes: RefCell::new(Vec::new()), @@ -2003,7 +2004,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let mut bcx = init_function(&fcx, false, output_type); if attributes.iter().any(|item| item.check_name("rustc_mir")) { - mir::trans_mir(bcx); + mir::trans_mir(bcx.build()); fcx.cleanup(); return; } diff --git a/src/librustc_trans/trans/build.rs b/src/librustc_trans/trans/build.rs index e501855b5d5f9..ce541c8d411bb 100644 --- a/src/librustc_trans/trans/build.rs +++ b/src/librustc_trans/trans/build.rs @@ -150,8 +150,7 @@ pub fn Invoke(cx: Block, cx.val_to_string(fn_), args.iter().map(|a| cx.val_to_string(*a)).collect::>().join(", ")); debug_loc.apply(cx.fcx); - let lpad = cx.lpad.borrow(); - let bundle = lpad.as_ref().and_then(|b| b.bundle()); + let bundle = cx.lpad().and_then(|b| b.bundle()); B(cx).invoke(fn_, args, then, catch, bundle, attributes) } @@ -916,8 +915,7 @@ pub fn Call(cx: Block, return _UndefReturn(cx, fn_); } debug_loc.apply(cx.fcx); - let lpad = cx.lpad.borrow(); - let bundle = lpad.as_ref().and_then(|b| b.bundle()); + let bundle = cx.lpad.get().and_then(|b| b.bundle()); B(cx).call(fn_, args, bundle, attributes) } @@ -932,8 +930,7 @@ pub fn CallWithConv(cx: Block, return _UndefReturn(cx, fn_); } debug_loc.apply(cx.fcx); - let lpad = cx.lpad.borrow(); - let bundle = lpad.as_ref().and_then(|b| b.bundle()); + let bundle = cx.lpad.get().and_then(|b| b.bundle()); B(cx).call_with_conv(fn_, args, conv, bundle, attributes) } diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 7c98868dfe7c6..683d5e0ead452 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -1054,11 +1054,11 @@ impl EarlyExitLabel { match *self { UnwindExit(UnwindKind::CleanupPad(..)) => { let pad = build::CleanupPad(bcx, None, &[]); - *bcx.lpad.borrow_mut() = Some(LandingPad::msvc(pad)); + bcx.lpad.set(Some(bcx.fcx.lpad_arena.alloc(LandingPad::msvc(pad)))); UnwindExit(UnwindKind::CleanupPad(pad)) } UnwindExit(UnwindKind::LandingPad) => { - *bcx.lpad.borrow_mut() = Some(LandingPad::gnu()); + bcx.lpad.set(Some(bcx.fcx.lpad_arena.alloc(LandingPad::gnu()))); *self } label => label, diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 303fc17ce81b4..ec33046e5d914 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -26,6 +26,7 @@ use middle::lang_items::LangItem; use middle::subst::{self, Substs}; use trans::base; use trans::build; +use trans::builder::Builder; use trans::callee; use trans::cleanup; use trans::consts; @@ -45,6 +46,7 @@ use util::nodemap::{FnvHashMap, NodeMap}; use arena::TypedArena; use libc::{c_uint, c_char}; +use std::ops::Deref; use std::ffi::CString; use std::cell::{Cell, RefCell}; use std::vec::Vec; @@ -365,6 +367,9 @@ pub struct FunctionContext<'a, 'tcx: 'a> { // The arena that blocks are allocated from. pub block_arena: &'a TypedArena>, + // The arena that landing pads are allocated from. + pub lpad_arena: TypedArena, + // This function's enclosing crate context. pub ccx: &'a CrateContext<'a, 'tcx>, @@ -582,7 +587,7 @@ pub struct BlockS<'blk, 'tcx: 'blk> { // If this block part of a landing pad, then this is `Some` indicating what // kind of landing pad its in, otherwise this is none. - pub lpad: RefCell>, + pub lpad: Cell>, // AST node-id associated with this block, if any. Used for // debugging purposes only. @@ -604,7 +609,7 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> { llbb: llbb, terminated: Cell::new(false), unreachable: Cell::new(false), - lpad: RefCell::new(None), + lpad: Cell::new(None), opt_node_id: opt_node_id, fcx: fcx }) @@ -613,11 +618,18 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> { pub fn ccx(&self) -> &'blk CrateContext<'blk, 'tcx> { self.fcx.ccx } + pub fn fcx(&self) -> &'blk FunctionContext<'blk, 'tcx> { + self.fcx + } pub fn tcx(&self) -> &'blk ty::ctxt<'tcx> { self.fcx.ccx.tcx() } pub fn sess(&self) -> &'blk Session { self.fcx.ccx.sess() } + pub fn lpad(&self) -> Option<&'blk LandingPad> { + self.lpad.get() + } + pub fn mir(&self) -> &'blk Mir<'tcx> { self.fcx.mir() } @@ -659,6 +671,109 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> { self.fcx.param_substs, value) } + + pub fn build(&'blk self) -> BlockAndBuilder<'blk, 'tcx> { + BlockAndBuilder::new(self, OwnedBuilder::new_with_ccx(self.ccx())) + } +} + +pub struct OwnedBuilder<'blk, 'tcx: 'blk> { + builder: Builder<'blk, 'tcx> +} + +impl<'blk, 'tcx> OwnedBuilder<'blk, 'tcx> { + pub fn new_with_ccx(ccx: &'blk CrateContext<'blk, 'tcx>) -> Self { + // Create a fresh builder from the crate context. + let llbuilder = unsafe { + llvm::LLVMCreateBuilderInContext(ccx.llcx()) + }; + OwnedBuilder { + builder: Builder { + llbuilder: llbuilder, + ccx: ccx, + } + } + } +} + +impl<'blk, 'tcx> Drop for OwnedBuilder<'blk, 'tcx> { + fn drop(&mut self) { + unsafe { + llvm::LLVMDisposeBuilder(self.builder.llbuilder); + } + } +} + +pub struct BlockAndBuilder<'blk, 'tcx: 'blk> { + bcx: Block<'blk, 'tcx>, + owned_builder: OwnedBuilder<'blk, 'tcx>, +} + +impl<'blk, 'tcx> BlockAndBuilder<'blk, 'tcx> { + pub fn new(bcx: Block<'blk, 'tcx>, owned_builder: OwnedBuilder<'blk, 'tcx>) -> Self { + // Set the builder's position to this block's end. + owned_builder.builder.position_at_end(bcx.llbb); + BlockAndBuilder { + bcx: bcx, + owned_builder: owned_builder, + } + } + + pub fn with_block(&self, f: F) -> R + where F: FnOnce(Block<'blk, 'tcx>) -> R + { + let result = f(self.bcx); + self.position_at_end(self.bcx.llbb); + result + } + + pub fn map_block(self, f: F) -> Self + where F: FnOnce(Block<'blk, 'tcx>) -> Block<'blk, 'tcx> + { + let BlockAndBuilder { bcx, owned_builder } = self; + let bcx = f(bcx); + BlockAndBuilder::new(bcx, owned_builder) + } + + // Methods delegated to bcx + + pub fn ccx(&self) -> &'blk CrateContext<'blk, 'tcx> { + self.bcx.ccx() + } + pub fn fcx(&self) -> &'blk FunctionContext<'blk, 'tcx> { + self.bcx.fcx() + } + pub fn tcx(&self) -> &'blk ty::ctxt<'tcx> { + self.bcx.tcx() + } + pub fn sess(&self) -> &'blk Session { + self.bcx.sess() + } + + pub fn llbb(&self) -> BasicBlockRef { + self.bcx.llbb + } + + pub fn mir(&self) -> &'blk Mir<'tcx> { + self.bcx.mir() + } + + pub fn val_to_string(&self, val: ValueRef) -> String { + self.bcx.val_to_string(val) + } + + pub fn monomorphize(&self, value: &T) -> T + where T: TypeFoldable<'tcx> + { + self.bcx.monomorphize(value) + } +} + +impl<'blk, 'tcx> Deref for BlockAndBuilder<'blk, 'tcx> { + type Target = Builder<'blk, 'tcx>; + fn deref(&self) -> &Self::Target { + &self.owned_builder.builder + } } /// A structure representing an active landing pad for the duration of a basic diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index 5be585c4189e1..b3b8214a9a70d 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -16,7 +16,7 @@ use trans::adt; use trans::attributes; use trans::base; use trans::build; -use trans::common::{self, Block, LandingPad}; +use trans::common::{self, Block, BlockAndBuilder}; use trans::debuginfo::DebugLoc; use trans::Disr; use trans::foreign; @@ -42,94 +42,98 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { match *data.terminator() { mir::Terminator::Goto { target } => { - build::Br(bcx, self.llblock(target), DebugLoc::None) + bcx.br(self.llblock(target)); } mir::Terminator::If { ref cond, targets: (true_bb, false_bb) } => { - let cond = self.trans_operand(bcx, cond); + let cond = self.trans_operand(&bcx, cond); let lltrue = self.llblock(true_bb); let llfalse = self.llblock(false_bb); - build::CondBr(bcx, cond.immediate(), lltrue, llfalse, DebugLoc::None); + bcx.cond_br(cond.immediate(), lltrue, llfalse); } mir::Terminator::Switch { ref discr, ref adt_def, ref targets } => { - let discr_lvalue = self.trans_lvalue(bcx, discr); + let discr_lvalue = self.trans_lvalue(&bcx, discr); let ty = discr_lvalue.ty.to_ty(bcx.tcx()); let repr = adt::represent_type(bcx.ccx(), ty); - let discr = adt::trans_get_discr(bcx, &repr, discr_lvalue.llval, - None, true); + let discr = bcx.with_block(|bcx| + adt::trans_get_discr(bcx, &repr, discr_lvalue.llval, None, true) + ); // The else branch of the Switch can't be hit, so branch to an unreachable // instruction so LLVM knows that let unreachable_blk = self.unreachable_block(); - let switch = build::Switch(bcx, discr, unreachable_blk.llbb, targets.len()); + let switch = bcx.switch(discr, unreachable_blk.llbb, targets.len()); assert_eq!(adt_def.variants.len(), targets.len()); for (adt_variant, target) in adt_def.variants.iter().zip(targets) { - let llval = adt::trans_case(bcx, &*repr, Disr::from(adt_variant.disr_val)); + let llval = bcx.with_block(|bcx| + adt::trans_case(bcx, &*repr, Disr::from(adt_variant.disr_val)) + ); let llbb = self.llblock(*target); - build::AddCase(switch, llval, llbb) } } mir::Terminator::SwitchInt { ref discr, switch_ty, ref values, ref targets } => { let (otherwise, targets) = targets.split_last().unwrap(); - let discr = build::Load(bcx, self.trans_lvalue(bcx, discr).llval); - let switch = build::Switch(bcx, discr, self.llblock(*otherwise), values.len()); + let discr = bcx.load(self.trans_lvalue(&bcx, discr).llval); + let switch = bcx.switch(discr, self.llblock(*otherwise), values.len()); for (value, target) in values.iter().zip(targets) { - let llval = self.trans_constval(bcx, value, switch_ty).immediate(); + let llval = self.trans_constval(&bcx, value, switch_ty).immediate(); let llbb = self.llblock(*target); build::AddCase(switch, llval, llbb) } } mir::Terminator::Resume => { - let ps = self.get_personality_slot(bcx); - let lp = build::Load(bcx, ps); - base::call_lifetime_end(bcx, ps); - base::trans_unwind_resume(bcx, lp); + let ps = self.get_personality_slot(&bcx); + let lp = bcx.load(ps); + bcx.with_block(|bcx| { + base::call_lifetime_end(bcx, ps); + base::trans_unwind_resume(bcx, lp); + }); } mir::Terminator::Return => { let return_ty = bcx.monomorphize(&self.mir.return_ty); - base::build_return_block(bcx.fcx, bcx, return_ty, DebugLoc::None); + bcx.with_block(|bcx| { + base::build_return_block(bcx.fcx, bcx, return_ty, DebugLoc::None); + }) } mir::Terminator::Drop { ref value, target, unwind } => { - let lvalue = self.trans_lvalue(bcx, value); + let lvalue = self.trans_lvalue(&bcx, value); let ty = lvalue.ty.to_ty(bcx.tcx()); // Double check for necessity to drop if !glue::type_needs_drop(bcx.tcx(), ty) { - build::Br(bcx, self.llblock(target), DebugLoc::None); + bcx.br(self.llblock(target)); return; } let drop_fn = glue::get_drop_glue(bcx.ccx(), ty); let drop_ty = glue::get_drop_glue_type(bcx.ccx(), ty); let llvalue = if drop_ty != ty { - build::PointerCast(bcx, lvalue.llval, - type_of::type_of(bcx.ccx(), drop_ty).ptr_to()) + bcx.pointercast(lvalue.llval, type_of::type_of(bcx.ccx(), drop_ty).ptr_to()) } else { lvalue.llval }; if let Some(unwind) = unwind { let uwbcx = self.bcx(unwind); let unwind = self.make_landing_pad(uwbcx); - build::Invoke(bcx, - drop_fn, - &[llvalue], - self.llblock(target), - unwind.llbb, - None, - DebugLoc::None); + bcx.invoke(drop_fn, + &[llvalue], + self.llblock(target), + unwind.llbb(), + None, + None); } else { - build::Call(bcx, drop_fn, &[llvalue], None, DebugLoc::None); - build::Br(bcx, self.llblock(target), DebugLoc::None); + bcx.call(drop_fn, &[llvalue], None, None); + bcx.br(self.llblock(target)); } } mir::Terminator::Call { ref func, ref args, ref destination, ref cleanup } => { // Create the callee. This will always be a fn ptr and hence a kind of scalar. - let callee = self.trans_operand(bcx, func); + let callee = self.trans_operand(&bcx, func); let attrs = attributes::from_fn_type(bcx.ccx(), callee.ty); let debugloc = DebugLoc::None; // The arguments we'll be passing. Plus one to account for outptr, if used. @@ -149,7 +153,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // Prepare the return value destination let (ret_dest_ty, must_copy_dest) = if let Some((ref d, _)) = *destination { - let dest = self.trans_lvalue(bcx, d); + let dest = self.trans_lvalue(&bcx, d); let ret_ty = dest.ty.to_ty(bcx.tcx()); if !is_foreign && type_of::return_uses_outptr(bcx.ccx(), ret_ty) { llargs.push(dest.llval); @@ -163,7 +167,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // Process the rest of the args. for arg in args { - let operand = self.trans_operand(bcx, arg); + let operand = self.trans_operand(&bcx, arg); match operand.val { Ref(llval) | Immediate(llval) => llargs.push(llval), FatPtr(b, e) => { @@ -176,38 +180,37 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } } + let avoid_invoke = bcx.with_block(|bcx| base::avoid_invoke(bcx)); // Many different ways to call a function handled here - match (is_foreign, base::avoid_invoke(bcx), cleanup, destination) { + match (is_foreign, avoid_invoke, cleanup, destination) { // The two cases below are the only ones to use LLVM’s `invoke`. (false, false, &Some(cleanup), &None) => { let cleanup = self.bcx(cleanup); let landingpad = self.make_landing_pad(cleanup); let unreachable_blk = self.unreachable_block(); - build::Invoke(bcx, - callee.immediate(), - &llargs[..], - unreachable_blk.llbb, - landingpad.llbb, - Some(attrs), - debugloc); + bcx.invoke(callee.immediate(), + &llargs[..], + unreachable_blk.llbb, + landingpad.llbb(), + None, + Some(attrs)); }, (false, false, &Some(cleanup), &Some((_, success))) => { let cleanup = self.bcx(cleanup); let landingpad = self.make_landing_pad(cleanup); let (target, postinvoke) = if must_copy_dest { - (bcx.fcx.new_block("", None), Some(self.bcx(success))) + (bcx.fcx().new_block("", None).build(), Some(self.bcx(success))) } else { (self.bcx(success), None) }; - let invokeret = build::Invoke(bcx, - callee.immediate(), - &llargs[..], - target.llbb, - landingpad.llbb, - Some(attrs), - debugloc); + let invokeret = bcx.invoke(callee.immediate(), + &llargs[..], + target.llbb(), + landingpad.llbb(), + None, + Some(attrs)); if let Some(postinvoketarget) = postinvoke { - // We translate the copy into a temoprary block. The temporary block is + // We translate the copy into a temporary block. The temporary block is // necessary because the current block has already been terminated (by // `invoke`) and we cannot really translate into the target block // because: @@ -233,40 +236,45 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // ; immediate precedesors let (ret_dest, ret_ty) = ret_dest_ty .expect("return destination and type not set"); - base::store_ty(target, invokeret, ret_dest.llval, ret_ty); - build::Br(target, postinvoketarget.llbb, debugloc); + target.with_block(|target| { + base::store_ty(target, invokeret, ret_dest.llval, ret_ty); + }); + target.br(postinvoketarget.llbb()); } }, (false, _, _, &None) => { - build::Call(bcx, callee.immediate(), &llargs[..], Some(attrs), debugloc); - build::Unreachable(bcx); + bcx.call(callee.immediate(), &llargs[..], None, Some(attrs)); + bcx.unreachable(); } (false, _, _, &Some((_, target))) => { - let llret = build::Call(bcx, - callee.immediate(), - &llargs[..], - Some(attrs), - debugloc); + let llret = bcx.call(callee.immediate(), + &llargs[..], + None, + Some(attrs)); if must_copy_dest { let (ret_dest, ret_ty) = ret_dest_ty .expect("return destination and type not set"); - base::store_ty(bcx, llret, ret_dest.llval, ret_ty); + bcx.with_block(|bcx| { + base::store_ty(bcx, llret, ret_dest.llval, ret_ty); + }); } - build::Br(bcx, self.llblock(target), debugloc); + bcx.br(self.llblock(target)); } // Foreign functions (true, _, _, destination) => { let (dest, _) = ret_dest_ty .expect("return destination is not set"); - bcx = foreign::trans_native_call(bcx, - callee.ty, - callee.immediate(), - dest.llval, - &llargs[..], - arg_tys, - debugloc); + bcx = bcx.map_block(|bcx| { + foreign::trans_native_call(bcx, + callee.ty, + callee.immediate(), + dest.llval, + &llargs[..], + arg_tys, + debugloc) + }); if let Some((_, target)) = *destination { - build::Br(bcx, self.llblock(target), debugloc); + bcx.br(self.llblock(target)); } }, } @@ -274,48 +282,49 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } } - fn get_personality_slot(&mut self, bcx: Block<'bcx, 'tcx>) -> ValueRef { + fn get_personality_slot(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>) -> ValueRef { let ccx = bcx.ccx(); if let Some(slot) = self.llpersonalityslot { slot } else { let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false); - let slot = base::alloca(bcx, llretty, "personalityslot"); - self.llpersonalityslot = Some(slot); - base::call_lifetime_start(bcx, slot); - slot + bcx.with_block(|bcx| { + let slot = base::alloca(bcx, llretty, "personalityslot"); + self.llpersonalityslot = Some(slot); + base::call_lifetime_start(bcx, slot); + slot + }) } } - fn make_landing_pad(&mut self, cleanup: Block<'bcx, 'tcx>) -> Block<'bcx, 'tcx> { - let bcx = cleanup.fcx.new_block("cleanup", None); + fn make_landing_pad(&mut self, + cleanup: BlockAndBuilder<'bcx, 'tcx>) + -> BlockAndBuilder<'bcx, 'tcx> + { // FIXME(#30941) this doesn't handle msvc-style exceptions - *bcx.lpad.borrow_mut() = Some(LandingPad::gnu()); + let bcx = self.fcx.new_block("cleanup", None).build(); let ccx = bcx.ccx(); - let llpersonality = bcx.fcx.eh_personality(); + let llpersonality = self.fcx.eh_personality(); let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false); - let llretval = build::LandingPad(bcx, llretty, llpersonality, 1); - build::SetCleanup(bcx, llretval); - let slot = self.get_personality_slot(bcx); - build::Store(bcx, llretval, slot); - build::Br(bcx, cleanup.llbb, DebugLoc::None); + let llretval = bcx.landing_pad(llretty, llpersonality, 1, self.fcx.llfn); + bcx.set_cleanup(llretval); + let slot = self.get_personality_slot(&bcx); + bcx.store(llretval, slot); + bcx.br(cleanup.llbb()); bcx } fn unreachable_block(&mut self) -> Block<'bcx, 'tcx> { - match self.unreachable_block { - Some(b) => b, - None => { - let bl = self.fcx.new_block("unreachable", None); - build::Unreachable(bl); - self.unreachable_block = Some(bl); - bl - } - } + self.unreachable_block.unwrap_or_else(|| { + let bl = self.fcx.new_block("unreachable", None); + bl.build().unreachable(); + self.unreachable_block = Some(bl); + bl + }) } - fn bcx(&self, bb: mir::BasicBlock) -> Block<'bcx, 'tcx> { - self.blocks[bb.index()] + fn bcx(&self, bb: mir::BasicBlock) -> BlockAndBuilder<'bcx, 'tcx> { + self.blocks[bb.index()].build() } fn llblock(&self, bb: mir::BasicBlock) -> BasicBlockRef { diff --git a/src/librustc_trans/trans/mir/constant.rs b/src/librustc_trans/trans/mir/constant.rs index 3b763599f7772..7f03069385fec 100644 --- a/src/librustc_trans/trans/mir/constant.rs +++ b/src/librustc_trans/trans/mir/constant.rs @@ -14,7 +14,8 @@ use middle::subst::Substs; use middle::ty::{Ty, TypeFoldable}; use rustc::middle::const_eval::ConstVal; use rustc::mir::repr as mir; -use trans::common::{self, Block, C_bool, C_bytes, C_floating_f64, C_integral, C_str_slice}; +use trans::common::{self, BlockAndBuilder, C_bool, C_bytes, C_floating_f64, C_integral, + C_str_slice}; use trans::consts; use trans::expr; use trans::type_of; @@ -25,13 +26,13 @@ use super::MirContext; impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn trans_constval(&mut self, - bcx: Block<'bcx, 'tcx>, + bcx: &BlockAndBuilder<'bcx, 'tcx>, cv: &ConstVal, ty: Ty<'tcx>) -> OperandRef<'tcx> { let ccx = bcx.ccx(); - let val = self.trans_constval_inner(bcx, cv, ty, bcx.fcx.param_substs); + let val = self.trans_constval_inner(bcx, cv, ty, bcx.fcx().param_substs); let val = if common::type_is_immediate(ccx, ty) { OperandValue::Immediate(val) } else if common::type_is_fat_ptr(bcx.tcx(), ty) { @@ -52,7 +53,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { /// Translate ConstVal into a bare LLVM ValueRef. fn trans_constval_inner(&mut self, - bcx: common::Block<'bcx, 'tcx>, + bcx: &BlockAndBuilder<'bcx, 'tcx>, cv: &ConstVal, ty: Ty<'tcx>, param_substs: &'tcx Substs<'tcx>) @@ -70,7 +71,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { ConstVal::Struct(id) | ConstVal::Tuple(id) | ConstVal::Array(id, _) | ConstVal::Repeat(id, _) => { let expr = bcx.tcx().map.expect_expr(id); - expr::trans(bcx, expr).datum.val + bcx.with_block(|bcx| { + expr::trans(bcx, expr).datum.val + }) }, ConstVal::Function(did) => self.trans_fn_ref(bcx, ty, param_substs, did).immediate() @@ -78,7 +81,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } pub fn trans_constant(&mut self, - bcx: Block<'bcx, 'tcx>, + bcx: &BlockAndBuilder<'bcx, 'tcx>, constant: &mir::Constant<'tcx>) -> OperandRef<'tcx> { diff --git a/src/librustc_trans/trans/mir/did.rs b/src/librustc_trans/trans/mir/did.rs index e433776bef293..36bbbce7ec46d 100644 --- a/src/librustc_trans/trans/mir/did.rs +++ b/src/librustc_trans/trans/mir/did.rs @@ -18,7 +18,7 @@ use rustc::middle::const_eval; use rustc::middle::def_id::DefId; use rustc::middle::traits; use rustc::mir::repr::ItemKind; -use trans::common::{Block, fulfill_obligation}; +use trans::common::{BlockAndBuilder, fulfill_obligation}; use trans::base; use trans::closure; use trans::expr; @@ -32,7 +32,7 @@ use super::operand::{OperandRef, OperandValue}; impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { /// Translate reference to item. pub fn trans_item_ref(&mut self, - bcx: Block<'bcx, 'tcx>, + bcx: &BlockAndBuilder<'bcx, 'tcx>, ty: Ty<'tcx>, kind: ItemKind, substs: &'tcx Substs<'tcx>, @@ -53,7 +53,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { .expect("def was const, but lookup_const_by_id failed"); // FIXME: this is falling back to translating from HIR. This is not easy to fix, // because we would have somehow adapt const_eval to work on MIR rather than HIR. - let d = expr::trans(bcx, expr); + let d = bcx.with_block(|bcx| { + expr::trans(bcx, expr) + }); OperandRef::from_rvalue_datum(d.datum.to_rvalue_datum(d.bcx, "").datum) } } @@ -66,7 +68,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { /// /// This is an adaptation of callee::trans_fn_ref_with_substs. pub fn trans_fn_ref(&mut self, - bcx: Block<'bcx, 'tcx>, + bcx: &BlockAndBuilder<'bcx, 'tcx>, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>, did: DefId) @@ -101,7 +103,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { /// /// This is an adaptation of meth::trans_static_method_callee pub fn trans_trait_method(&mut self, - bcx: Block<'bcx, 'tcx>, + bcx: &BlockAndBuilder<'bcx, 'tcx>, ty: Ty<'tcx>, method_id: DefId, trait_id: DefId, diff --git a/src/librustc_trans/trans/mir/lvalue.rs b/src/librustc_trans/trans/mir/lvalue.rs index d994f1ea7b0b7..002584f51c6d7 100644 --- a/src/librustc_trans/trans/mir/lvalue.rs +++ b/src/librustc_trans/trans/mir/lvalue.rs @@ -14,9 +14,7 @@ use rustc::mir::repr as mir; use rustc::mir::tcx::LvalueTy; use trans::adt; use trans::base; -use trans::build; -use trans::common::{self, Block}; -use trans::debuginfo::DebugLoc; +use trans::common::{self, BlockAndBuilder}; use trans::machine; use trans::type_of; use llvm; @@ -43,20 +41,20 @@ impl<'tcx> LvalueRef<'tcx> { LvalueRef { llval: llval, llextra: ptr::null_mut(), ty: lvalue_ty } } - pub fn alloca<'bcx>(bcx: Block<'bcx, 'tcx>, + pub fn alloca<'bcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, ty: Ty<'tcx>, name: &str) -> LvalueRef<'tcx> { assert!(!ty.has_erasable_regions()); - let lltemp = base::alloc_ty(bcx, ty, name); + let lltemp = bcx.with_block(|bcx| base::alloc_ty(bcx, ty, name)); LvalueRef::new_sized(lltemp, LvalueTy::from_ty(ty)) } } impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn lvalue_len(&mut self, - bcx: Block<'bcx, 'tcx>, + bcx: &BlockAndBuilder<'bcx, 'tcx>, lvalue: LvalueRef<'tcx>) -> ValueRef { match lvalue.ty.to_ty(bcx.tcx()).sty { @@ -70,13 +68,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } pub fn trans_lvalue(&mut self, - bcx: Block<'bcx, 'tcx>, + bcx: &BlockAndBuilder<'bcx, 'tcx>, lvalue: &mir::Lvalue<'tcx>) -> LvalueRef<'tcx> { debug!("trans_lvalue(lvalue={:?})", lvalue); - let fcx = bcx.fcx; - let ccx = fcx.ccx; + let fcx = bcx.fcx(); + let ccx = bcx.ccx(); let tcx = bcx.tcx(); match *lvalue { mir::Lvalue::Var(index) => self.vars[index as usize], @@ -97,7 +95,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let fn_return_ty = bcx.monomorphize(&self.mir.return_ty); let return_ty = fn_return_ty.unwrap(); let llval = if !common::return_type_is_void(bcx.ccx(), return_ty) { - fcx.get_ret_slot(bcx, fn_return_ty, "") + bcx.with_block(|bcx| { + fcx.get_ret_slot(bcx, fn_return_ty, "") + }) } else { // This is a void return; that is, there’s no place to store the value and // there cannot really be one (or storing into it doesn’t make sense, anyway). @@ -117,12 +117,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let (llprojected, llextra) = match projection.elem { mir::ProjectionElem::Deref => { let base_ty = tr_base.ty.to_ty(tcx); - if common::type_is_sized(tcx, projected_ty.to_ty(tcx)) { - (base::load_ty(bcx, tr_base.llval, base_ty), - ptr::null_mut()) - } else { - base::load_fat_ptr(bcx, tr_base.llval, base_ty) - } + bcx.with_block(|bcx| { + if common::type_is_sized(tcx, projected_ty.to_ty(tcx)) { + (base::load_ty(bcx, tr_base.llval, base_ty), + ptr::null_mut()) + } else { + base::load_fat_ptr(bcx, tr_base.llval, base_ty) + } + }) } mir::ProjectionElem::Field(ref field) => { let base_ty = tr_base.ty.to_ty(tcx); @@ -138,18 +140,21 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } else { adt::MaybeSizedValue::unsized_(tr_base.llval, tr_base.llextra) }; - (adt::trans_field_ptr(bcx, &base_repr, base, Disr(discr), field.index()), - if is_sized { - ptr::null_mut() - } else { - tr_base.llextra - }) + let llprojected = bcx.with_block(|bcx| { + adt::trans_field_ptr(bcx, &base_repr, base, Disr(discr), field.index()) + }); + let llextra = if is_sized { + ptr::null_mut() + } else { + tr_base.llextra + }; + (llprojected, llextra) } mir::ProjectionElem::Index(ref index) => { let index = self.trans_operand(bcx, index); let llindex = self.prepare_index(bcx, index.immediate()); let zero = common::C_uint(bcx.ccx(), 0u64); - (build::InBoundsGEP(bcx, tr_base.llval, &[zero, llindex]), + (bcx.inbounds_gep(tr_base.llval, &[zero, llindex]), ptr::null_mut()) } mir::ProjectionElem::ConstantIndex { offset, @@ -158,7 +163,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let lloffset = common::C_u32(bcx.ccx(), offset); let llindex = self.prepare_index(bcx, lloffset); let zero = common::C_uint(bcx.ccx(), 0u64); - (build::InBoundsGEP(bcx, tr_base.llval, &[zero, llindex]), + (bcx.inbounds_gep(tr_base.llval, &[zero, llindex]), ptr::null_mut()) } mir::ProjectionElem::ConstantIndex { offset, @@ -166,10 +171,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { min_length: _ } => { let lloffset = common::C_u32(bcx.ccx(), offset); let lllen = self.lvalue_len(bcx, tr_base); - let llindex = build::Sub(bcx, lllen, lloffset, DebugLoc::None); + let llindex = bcx.sub(lllen, lloffset); let llindex = self.prepare_index(bcx, llindex); let zero = common::C_uint(bcx.ccx(), 0u64); - (build::InBoundsGEP(bcx, tr_base.llval, &[zero, llindex]), + (bcx.inbounds_gep(tr_base.llval, &[zero, llindex]), ptr::null_mut()) } mir::ProjectionElem::Downcast(..) => { @@ -190,7 +195,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { /// /// nmatsakis: is this still necessary? Not sure. fn prepare_index(&mut self, - bcx: Block<'bcx, 'tcx>, + bcx: &BlockAndBuilder<'bcx, 'tcx>, llindex: ValueRef) -> ValueRef { @@ -198,9 +203,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let index_size = machine::llbitsize_of_real(bcx.ccx(), common::val_ty(llindex)); let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type()); if index_size < int_size { - build::ZExt(bcx, llindex, ccx.int_type()) + bcx.zext(llindex, ccx.int_type()) } else if index_size > int_size { - build::Trunc(bcx, llindex, ccx.int_type()) + bcx.trunc(llindex, ccx.int_type()) } else { llindex } diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs index b19ecc45a4e5e..972340e7f5afd 100644 --- a/src/librustc_trans/trans/mir/mod.rs +++ b/src/librustc_trans/trans/mir/mod.rs @@ -13,9 +13,7 @@ use llvm::{self, ValueRef}; use rustc::mir::repr as mir; use rustc::mir::tcx::LvalueTy; use trans::base; -use trans::build; -use trans::common::{self, Block, LandingPad}; -use trans::debuginfo::DebugLoc; +use trans::common::{self, Block, BlockAndBuilder}; use trans::expr; use trans::type_of; @@ -79,26 +77,28 @@ enum TempRef<'tcx> { /////////////////////////////////////////////////////////////////////////// -pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) { - let fcx = bcx.fcx; +pub fn trans_mir<'bcx, 'tcx>(bcx: BlockAndBuilder<'bcx, 'tcx>) { + let fcx = bcx.fcx(); let mir = bcx.mir(); let mir_blocks = bcx.mir().all_basic_blocks(); // Analyze the temps to determine which must be lvalues // FIXME - let lvalue_temps = analyze::lvalue_temps(bcx, mir); + let lvalue_temps = bcx.with_block(|bcx| { + analyze::lvalue_temps(bcx, mir) + }); // Allocate variable and temp allocas let vars = mir.var_decls.iter() .map(|decl| (bcx.monomorphize(&decl.ty), decl.name)) - .map(|(mty, name)| LvalueRef::alloca(bcx, mty, &name.as_str())) + .map(|(mty, name)| LvalueRef::alloca(&bcx, mty, &name.as_str())) .collect(); let temps = mir.temp_decls.iter() .map(|decl| bcx.monomorphize(&decl.ty)) .enumerate() .map(|(i, mty)| if lvalue_temps.contains(i) { - TempRef::Lvalue(LvalueRef::alloca(bcx, + TempRef::Lvalue(LvalueRef::alloca(&bcx, mty, &format!("temp{:?}", i))) } else { @@ -108,24 +108,20 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) { TempRef::Operand(None) }) .collect(); - let args = arg_value_refs(bcx, mir); + let args = arg_value_refs(&bcx, mir); // Allocate a `Block` for every basic block let block_bcxs: Vec> = mir_blocks.iter() .map(|&bb|{ - let bcx = fcx.new_block(&format!("{:?}", bb), None); // FIXME(#30941) this doesn't handle msvc-style exceptions - if mir.basic_block_data(bb).is_cleanup { - *bcx.lpad.borrow_mut() = Some(LandingPad::gnu()) - } - bcx + fcx.new_block(&format!("{:?}", bb), None) }) .collect(); // Branch to the START block let start_bcx = block_bcxs[mir::START_BLOCK.index()]; - build::Br(bcx, start_bcx.llbb, DebugLoc::None); + bcx.br(start_bcx.llbb); let mut mircx = MirContext { mir: mir, @@ -147,11 +143,11 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) { /// Produce, for each argument, a `ValueRef` pointing at the /// argument's value. As arguments are lvalues, these are always /// indirect. -fn arg_value_refs<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>, +fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, mir: &mir::Mir<'tcx>) -> Vec> { // FIXME tupled_args? I think I'd rather that mapping is done in MIR land though - let fcx = bcx.fcx; + let fcx = bcx.fcx(); let tcx = bcx.tcx(); let mut idx = fcx.arg_offset() as c_uint; mir.arg_decls @@ -174,18 +170,23 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>, let lldata = llvm::get_param(fcx.llfn, idx); let llextra = llvm::get_param(fcx.llfn, idx + 1); idx += 2; - let lltemp = base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index)); - build::Store(bcx, lldata, expr::get_dataptr(bcx, lltemp)); - build::Store(bcx, llextra, expr::get_meta(bcx, lltemp)); + let (lltemp, dataptr, meta) = bcx.with_block(|bcx| { + let lltemp = base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index)); + (lltemp, expr::get_dataptr(bcx, lltemp), expr::get_meta(bcx, lltemp)) + }); + bcx.store(lldata, dataptr); + bcx.store(llextra, meta); lltemp } else { // otherwise, arg is passed by value, so make a // temporary and store it there let llarg = llvm::get_param(fcx.llfn, idx); idx += 1; - let lltemp = base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index)); - base::store_ty(bcx, llarg, lltemp, arg_ty); - lltemp + bcx.with_block(|bcx| { + let lltemp = base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index)); + base::store_ty(bcx, llarg, lltemp, arg_ty); + lltemp + }) }; LvalueRef::new_sized(llval, LvalueTy::from_ty(arg_ty)) }) diff --git a/src/librustc_trans/trans/mir/operand.rs b/src/librustc_trans/trans/mir/operand.rs index 114e78b05bddd..d0eaaeef05771 100644 --- a/src/librustc_trans/trans/mir/operand.rs +++ b/src/librustc_trans/trans/mir/operand.rs @@ -12,7 +12,7 @@ use llvm::ValueRef; use rustc::middle::ty::{Ty, TypeFoldable}; use rustc::mir::repr as mir; use trans::base; -use trans::common::{self, Block}; +use trans::common::{self, Block, BlockAndBuilder}; use trans::datum; use super::{MirContext, TempRef}; @@ -37,8 +37,9 @@ pub enum OperandValue { /// /// NOTE: unless you know a value's type exactly, you should not /// generate LLVM opcodes acting on it and instead act via methods, -/// to avoid nasty edge cases. In particular, using `build::Store` -/// directly is sure to cause problems - use `store_operand` instead. +/// to avoid nasty edge cases. In particular, using `Builder.store` +/// directly is sure to cause problems -- use `MirContext.store_operand` +/// instead. #[derive(Copy, Clone)] pub struct OperandRef<'tcx> { // The value. @@ -58,7 +59,7 @@ impl<'tcx> OperandRef<'tcx> { } } - pub fn repr<'bcx>(self, bcx: Block<'bcx, 'tcx>) -> String { + pub fn repr<'bcx>(self, bcx: &BlockAndBuilder<'bcx, 'tcx>) -> String { match self.val { OperandValue::Ref(r) => { format!("OperandRef(Ref({}) @ {:?})", @@ -90,7 +91,7 @@ impl<'tcx> OperandRef<'tcx> { impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn trans_operand(&mut self, - bcx: Block<'bcx, 'tcx>, + bcx: &BlockAndBuilder<'bcx, 'tcx>, operand: &mir::Operand<'tcx>) -> OperandRef<'tcx> { @@ -124,10 +125,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { ty); let val = match datum::appropriate_rvalue_mode(bcx.ccx(), ty) { datum::ByValue => { - OperandValue::Immediate(base::load_ty(bcx, tr_lvalue.llval, ty)) + bcx.with_block(|bcx| { + OperandValue::Immediate(base::load_ty(bcx, tr_lvalue.llval, ty)) + }) } datum::ByRef if common::type_is_fat_ptr(bcx.tcx(), ty) => { - let (lldata, llextra) = base::load_fat_ptr(bcx, tr_lvalue.llval, ty); + let (lldata, llextra) = bcx.with_block(|bcx| { + base::load_fat_ptr(bcx, tr_lvalue.llval, ty) + }); OperandValue::FatPtr(lldata, llextra) } datum::ByRef => OperandValue::Ref(tr_lvalue.llval) @@ -148,7 +153,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } pub fn trans_operand_into(&mut self, - bcx: Block<'bcx, 'tcx>, + bcx: &BlockAndBuilder<'bcx, 'tcx>, lldest: ValueRef, operand: &mir::Operand<'tcx>) { @@ -164,11 +169,21 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } pub fn store_operand(&mut self, - bcx: Block<'bcx, 'tcx>, + bcx: &BlockAndBuilder<'bcx, 'tcx>, lldest: ValueRef, operand: OperandRef<'tcx>) { debug!("store_operand: operand={}", operand.repr(bcx)); + bcx.with_block(|bcx| { + self.store_operand_direct(bcx, lldest, operand) + }) + } + + pub fn store_operand_direct(&mut self, + bcx: Block<'bcx, 'tcx>, + lldest: ValueRef, + operand: OperandRef<'tcx>) + { // Avoid generating stores of zero-sized values, because the only way to have a zero-sized // value is through `undef`, and store itself is useless. if common::type_is_zero_size(bcx.ccx(), operand.ty) { diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs index e280eff34c894..ab0c299af05ce 100644 --- a/src/librustc_trans/trans/mir/rvalue.rs +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -15,8 +15,7 @@ use rustc::mir::repr as mir; use trans::asm; use trans::base; -use trans::build; -use trans::common::{self, Block, Result}; +use trans::common::{self, BlockAndBuilder, Result}; use trans::debuginfo::DebugLoc; use trans::declare; use trans::expr; @@ -33,10 +32,10 @@ use super::lvalue::LvalueRef; impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn trans_rvalue(&mut self, - bcx: Block<'bcx, 'tcx>, + bcx: BlockAndBuilder<'bcx, 'tcx>, dest: LvalueRef<'tcx>, rvalue: &mir::Rvalue<'tcx>) - -> Block<'bcx, 'tcx> + -> BlockAndBuilder<'bcx, 'tcx> { debug!("trans_rvalue(dest.llval={}, rvalue={:?})", bcx.val_to_string(dest.llval), @@ -44,7 +43,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { match *rvalue { mir::Rvalue::Use(ref operand) => { - self.trans_operand_into(bcx, dest.llval, operand); + self.trans_operand_into(&bcx, dest.llval, operand); bcx } @@ -53,7 +52,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // into-coerce of a thin pointer to a fat pointer - just // use the operand path. let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); - self.store_operand(bcx, dest.llval, temp); + self.store_operand(&bcx, dest.llval, temp); return bcx; } @@ -61,39 +60,43 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // this to be eliminated by MIR translation, but // `CoerceUnsized` can be passed by a where-clause, // so the (generic) MIR may not be able to expand it. - let operand = self.trans_operand(bcx, operand); - match operand.val { - OperandValue::FatPtr(..) => unreachable!(), - OperandValue::Immediate(llval) => { - // unsize from an immediate structure. We don't - // really need a temporary alloca here, but - // avoiding it would require us to have - // `coerce_unsized_into` use extractvalue to - // index into the struct, and this case isn't - // important enough for it. - debug!("trans_rvalue: creating ugly alloca"); - let lltemp = base::alloc_ty(bcx, operand.ty, "__unsize_temp"); - base::store_ty(bcx, llval, lltemp, operand.ty); - base::coerce_unsized_into(bcx, - lltemp, operand.ty, - dest.llval, cast_ty); - } - OperandValue::Ref(llref) => { - base::coerce_unsized_into(bcx, - llref, operand.ty, - dest.llval, cast_ty); + let operand = self.trans_operand(&bcx, operand); + bcx.with_block(|bcx| { + match operand.val { + OperandValue::FatPtr(..) => unreachable!(), + OperandValue::Immediate(llval) => { + // unsize from an immediate structure. We don't + // really need a temporary alloca here, but + // avoiding it would require us to have + // `coerce_unsized_into` use extractvalue to + // index into the struct, and this case isn't + // important enough for it. + debug!("trans_rvalue: creating ugly alloca"); + let lltemp = base::alloc_ty(bcx, operand.ty, "__unsize_temp"); + base::store_ty(bcx, llval, lltemp, operand.ty); + base::coerce_unsized_into(bcx, + lltemp, operand.ty, + dest.llval, cast_ty); + } + OperandValue::Ref(llref) => { + base::coerce_unsized_into(bcx, + llref, operand.ty, + dest.llval, cast_ty); + } } - } + }); bcx } mir::Rvalue::Repeat(ref elem, ref count) => { - let elem = self.trans_operand(bcx, elem); - let size = self.trans_constval(bcx, &count.value, count.ty).immediate(); - let base = expr::get_dataptr(bcx, dest.llval); - tvec::iter_vec_raw(bcx, base, elem.ty, size, |bcx, llslot, _| { - self.store_operand(bcx, llslot, elem); - bcx + let elem = self.trans_operand(&bcx, elem); + let size = self.trans_constval(&bcx, &count.value, count.ty).immediate(); + bcx.map_block(|block| { + let base = expr::get_dataptr(block, dest.llval); + tvec::iter_vec_raw(block, base, elem.ty, size, |block, llslot, _| { + self.store_operand_direct(block, llslot, elem); + block + }) }) } @@ -102,27 +105,31 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { mir::AggregateKind::Adt(adt_def, index, _) => { let repr = adt::represent_type(bcx.ccx(), dest.ty.to_ty(bcx.tcx())); let disr = Disr::from(adt_def.variants[index].disr_val); - adt::trans_set_discr(bcx, &*repr, dest.llval, Disr::from(disr)); + bcx.with_block(|bcx| { + adt::trans_set_discr(bcx, &*repr, dest.llval, Disr::from(disr)); + }); for (i, operand) in operands.iter().enumerate() { - let op = self.trans_operand(bcx, operand); + let op = self.trans_operand(&bcx, operand); // Do not generate stores and GEPis for zero-sized fields. if !common::type_is_zero_size(bcx.ccx(), op.ty) { let val = adt::MaybeSizedValue::sized(dest.llval); - let lldest_i = adt::trans_field_ptr(bcx, &*repr, val, disr, i); - self.store_operand(bcx, lldest_i, op); + let lldest_i = bcx.with_block(|bcx| { + adt::trans_field_ptr(bcx, &*repr, val, disr, i) + }); + self.store_operand(&bcx, lldest_i, op); } } }, _ => { for (i, operand) in operands.iter().enumerate() { - let op = self.trans_operand(bcx, operand); + let op = self.trans_operand(&bcx, operand); // Do not generate stores and GEPis for zero-sized fields. if !common::type_is_zero_size(bcx.ccx(), op.ty) { // Note: perhaps this should be StructGep, but // note that in some cases the values here will // not be structs but arrays. - let dest = build::GEPi(bcx, dest.llval, &[0, i]); - self.store_operand(bcx, dest, op); + let dest = bcx.gepi(dest.llval, &[0, i]); + self.store_operand(&bcx, dest, op); } } } @@ -132,49 +139,54 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { mir::Rvalue::Slice { ref input, from_start, from_end } => { let ccx = bcx.ccx(); - let input = self.trans_lvalue(bcx, input); - let (llbase, lllen) = tvec::get_base_and_len(bcx, - input.llval, - input.ty.to_ty(bcx.tcx())); - let llbase1 = build::GEPi(bcx, llbase, &[from_start]); + let input = self.trans_lvalue(&bcx, input); + let (llbase, lllen) = bcx.with_block(|bcx| { + tvec::get_base_and_len(bcx, + input.llval, + input.ty.to_ty(bcx.tcx())) + }); + let llbase1 = bcx.gepi(llbase, &[from_start]); let adj = common::C_uint(ccx, from_start + from_end); - let lllen1 = build::Sub(bcx, lllen, adj, DebugLoc::None); - let lladdrdest = expr::get_dataptr(bcx, dest.llval); - build::Store(bcx, llbase1, lladdrdest); - let llmetadest = expr::get_meta(bcx, dest.llval); - build::Store(bcx, lllen1, llmetadest); + let lllen1 = bcx.sub(lllen, adj); + let (lladdrdest, llmetadest) = bcx.with_block(|bcx| { + (expr::get_dataptr(bcx, dest.llval), expr::get_meta(bcx, dest.llval)) + }); + bcx.store(llbase1, lladdrdest); + bcx.store(lllen1, llmetadest); bcx } mir::Rvalue::InlineAsm(ref inline_asm) => { - asm::trans_inline_asm(bcx, inline_asm) + bcx.map_block(|bcx| { + asm::trans_inline_asm(bcx, inline_asm) + }) } _ => { assert!(rvalue_creates_operand(rvalue)); let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); - self.store_operand(bcx, dest.llval, temp); + self.store_operand(&bcx, dest.llval, temp); bcx } } } pub fn trans_rvalue_operand(&mut self, - bcx: Block<'bcx, 'tcx>, + bcx: BlockAndBuilder<'bcx, 'tcx>, rvalue: &mir::Rvalue<'tcx>) - -> (Block<'bcx, 'tcx>, OperandRef<'tcx>) + -> (BlockAndBuilder<'bcx, 'tcx>, OperandRef<'tcx>) { assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); match *rvalue { mir::Rvalue::Use(ref operand) => { - let operand = self.trans_operand(bcx, operand); + let operand = self.trans_operand(&bcx, operand); (bcx, operand) } mir::Rvalue::Cast(ref kind, ref operand, cast_ty) => { - let operand = self.trans_operand(bcx, operand); - debug!("cast operand is {}", operand.repr(bcx)); + let operand = self.trans_operand(&bcx, operand); + debug!("cast operand is {}", operand.repr(&bcx)); let cast_ty = bcx.monomorphize(&cast_ty); let val = match *kind { @@ -199,15 +211,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } OperandValue::Immediate(lldata) => { // "standard" unsize - let (lldata, llextra) = + let (lldata, llextra) = bcx.with_block(|bcx| { base::unsize_thin_ptr(bcx, lldata, - operand.ty, cast_ty); + operand.ty, cast_ty) + }); OperandValue::FatPtr(lldata, llextra) } OperandValue::Ref(_) => { bcx.sess().bug( &format!("by-ref operand {} in trans_rvalue_operand", - operand.repr(bcx))); + operand.repr(&bcx))); } } } @@ -220,8 +233,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let (llval, ll_t_in, signed) = if let CastTy::Int(IntTy::CEnum) = r_t_in { let repr = adt::represent_type(bcx.ccx(), operand.ty); let llval = operand.immediate(); - let discr = adt::trans_get_discr(bcx, &*repr, llval, - None, true); + let discr = bcx.with_block(|bcx| { + adt::trans_get_discr(bcx, &*repr, llval, None, true) + }); (discr, common::val_ty(discr), adt::is_discr_signed(&*repr)) } else { (operand.immediate(), ll_t_in, operand.ty.is_signed()) @@ -232,22 +246,22 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let srcsz = ll_t_in.int_width(); let dstsz = ll_t_out.int_width(); if srcsz == dstsz { - build::BitCast(bcx, llval, ll_t_out) + bcx.bitcast(llval, ll_t_out) } else if srcsz > dstsz { - build::Trunc(bcx, llval, ll_t_out) + bcx.trunc(llval, ll_t_out) } else if signed { - build::SExt(bcx, llval, ll_t_out) + bcx.sext(llval, ll_t_out) } else { - build::ZExt(bcx, llval, ll_t_out) + bcx.zext(llval, ll_t_out) } } (CastTy::Float, CastTy::Float) => { let srcsz = ll_t_in.float_width(); let dstsz = ll_t_out.float_width(); if dstsz > srcsz { - build::FPExt(bcx, llval, ll_t_out) + bcx.fpext(llval, ll_t_out) } else if srcsz > dstsz { - build::FPTrunc(bcx, llval, ll_t_out) + bcx.fptrunc(llval, ll_t_out) } else { llval } @@ -255,20 +269,20 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { (CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FnPtr, CastTy::Ptr(_)) | (CastTy::RPtr(_), CastTy::Ptr(_)) => - build::PointerCast(bcx, llval, ll_t_out), + bcx.pointercast(llval, ll_t_out), (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => - build::PtrToInt(bcx, llval, ll_t_out), + bcx.ptrtoint(llval, ll_t_out), (CastTy::Int(_), CastTy::Ptr(_)) => - build::IntToPtr(bcx, llval, ll_t_out), + bcx.inttoptr(llval, ll_t_out), (CastTy::Int(_), CastTy::Float) if signed => - build::SIToFP(bcx, llval, ll_t_out), + bcx.sitofp(llval, ll_t_out), (CastTy::Int(_), CastTy::Float) => - build::UIToFP(bcx, llval, ll_t_out), + bcx.uitofp(llval, ll_t_out), (CastTy::Float, CastTy::Int(IntTy::I)) => - build::FPToSI(bcx, llval, ll_t_out), + bcx.fptosi(llval, ll_t_out), (CastTy::Float, CastTy::Int(_)) => - build::FPToUI(bcx, llval, ll_t_out), + bcx.fptoui(llval, ll_t_out), _ => bcx.ccx().sess().bug( &format!("unsupported cast: {:?} to {:?}", operand.ty, cast_ty) ) @@ -282,13 +296,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { if common::type_is_fat_ptr(bcx.tcx(), cast_ty) { let ll_cft = ll_cast_ty.field_types(); let ll_fft = ll_from_ty.field_types(); - let data_cast = build::PointerCast(bcx, data_ptr, ll_cft[0]); + let data_cast = bcx.pointercast(data_ptr, ll_cft[0]); assert_eq!(ll_cft[1].kind(), ll_fft[1].kind()); OperandValue::FatPtr(data_cast, meta_ptr) } else { // cast to thin-ptr // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and // pointer-cast of that pointer to desired pointer type. - let llval = build::PointerCast(bcx, data_ptr, ll_cast_ty); + let llval = bcx.pointercast(data_ptr, ll_cast_ty); OperandValue::Immediate(llval) } } else { @@ -296,14 +310,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } } }; - (bcx, OperandRef { + let operand = OperandRef { val: val, ty: cast_ty - }) + }; + (bcx, operand) } mir::Rvalue::Ref(_, bk, ref lvalue) => { - let tr_lvalue = self.trans_lvalue(bcx, lvalue); + let tr_lvalue = self.trans_lvalue(&bcx, lvalue); let ty = tr_lvalue.ty.to_ty(bcx.tcx()); let ref_ty = bcx.tcx().mk_ref( @@ -313,66 +328,70 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // Note: lvalues are indirect, so storing the `llval` into the // destination effectively creates a reference. - if common::type_is_sized(bcx.tcx(), ty) { - (bcx, OperandRef { + let operand = if common::type_is_sized(bcx.tcx(), ty) { + OperandRef { val: OperandValue::Immediate(tr_lvalue.llval), ty: ref_ty, - }) + } } else { - (bcx, OperandRef { + OperandRef { val: OperandValue::FatPtr(tr_lvalue.llval, tr_lvalue.llextra), ty: ref_ty, - }) - } + } + }; + (bcx, operand) } mir::Rvalue::Len(ref lvalue) => { - let tr_lvalue = self.trans_lvalue(bcx, lvalue); - (bcx, OperandRef { - val: OperandValue::Immediate(self.lvalue_len(bcx, tr_lvalue)), + let tr_lvalue = self.trans_lvalue(&bcx, lvalue); + let operand = OperandRef { + val: OperandValue::Immediate(self.lvalue_len(&bcx, tr_lvalue)), ty: bcx.tcx().types.usize, - }) + }; + (bcx, operand) } mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => { - let lhs = self.trans_operand(bcx, lhs); - let rhs = self.trans_operand(bcx, rhs); + let lhs = self.trans_operand(&bcx, lhs); + let rhs = self.trans_operand(&bcx, rhs); let llresult = if common::type_is_fat_ptr(bcx.tcx(), lhs.ty) { match (lhs.val, rhs.val) { (OperandValue::FatPtr(lhs_addr, lhs_extra), OperandValue::FatPtr(rhs_addr, rhs_extra)) => { - base::compare_fat_ptrs(bcx, - lhs_addr, lhs_extra, - rhs_addr, rhs_extra, - lhs.ty, op.to_hir_binop(), - DebugLoc::None) + bcx.with_block(|bcx| { + base::compare_fat_ptrs(bcx, + lhs_addr, lhs_extra, + rhs_addr, rhs_extra, + lhs.ty, op.to_hir_binop(), + DebugLoc::None) + }) } _ => unreachable!() } } else { - self.trans_scalar_binop(bcx, op, + self.trans_scalar_binop(&bcx, op, lhs.immediate(), rhs.immediate(), - lhs.ty, DebugLoc::None) + lhs.ty) }; - (bcx, OperandRef { + let operand = OperandRef { val: OperandValue::Immediate(llresult), ty: self.mir.binop_ty(bcx.tcx(), op, lhs.ty, rhs.ty), - }) + }; + (bcx, operand) } mir::Rvalue::UnaryOp(op, ref operand) => { - let operand = self.trans_operand(bcx, operand); + let operand = self.trans_operand(&bcx, operand); let lloperand = operand.immediate(); let is_float = operand.ty.is_fp(); - let debug_loc = DebugLoc::None; let llval = match op { - mir::UnOp::Not => build::Not(bcx, lloperand, debug_loc), + mir::UnOp::Not => bcx.not(lloperand), mir::UnOp::Neg => if is_float { - build::FNeg(bcx, lloperand, debug_loc) + bcx.fneg(lloperand) } else { - build::Neg(bcx, lloperand, debug_loc) + bcx.neg(lloperand) } }; (bcx, OperandRef { @@ -389,16 +408,22 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let llalign = common::C_uint(bcx.ccx(), align); let llty_ptr = llty.ptr_to(); let box_ty = bcx.tcx().mk_box(content_ty); - let Result { bcx, val: llval } = base::malloc_raw_dyn(bcx, - llty_ptr, - box_ty, - llsize, - llalign, - DebugLoc::None); - (bcx, OperandRef { - val: OperandValue::Immediate(llval), + let mut llval = None; + let bcx = bcx.map_block(|bcx| { + let Result { bcx, val } = base::malloc_raw_dyn(bcx, + llty_ptr, + box_ty, + llsize, + llalign, + DebugLoc::None); + llval = Some(val); + bcx + }); + let operand = OperandRef { + val: OperandValue::Immediate(llval.unwrap()), ty: box_ty, - }) + }; + (bcx, operand) } mir::Rvalue::Repeat(..) | @@ -411,36 +436,35 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } pub fn trans_scalar_binop(&mut self, - bcx: Block<'bcx, 'tcx>, + bcx: &BlockAndBuilder<'bcx, 'tcx>, op: mir::BinOp, lhs: ValueRef, rhs: ValueRef, - input_ty: Ty<'tcx>, - debug_loc: DebugLoc) -> ValueRef { + input_ty: Ty<'tcx>) -> ValueRef { let is_float = input_ty.is_fp(); let is_signed = input_ty.is_signed(); match op { mir::BinOp::Add => if is_float { - build::FAdd(bcx, lhs, rhs, debug_loc) + bcx.fadd(lhs, rhs) } else { - build::Add(bcx, lhs, rhs, debug_loc) + bcx.add(lhs, rhs) }, mir::BinOp::Sub => if is_float { - build::FSub(bcx, lhs, rhs, debug_loc) + bcx.fsub(lhs, rhs) } else { - build::Sub(bcx, lhs, rhs, debug_loc) + bcx.sub(lhs, rhs) }, mir::BinOp::Mul => if is_float { - build::FMul(bcx, lhs, rhs, debug_loc) + bcx.fmul(lhs, rhs) } else { - build::Mul(bcx, lhs, rhs, debug_loc) + bcx.mul(lhs, rhs) }, mir::BinOp::Div => if is_float { - build::FDiv(bcx, lhs, rhs, debug_loc) + bcx.fdiv(lhs, rhs) } else if is_signed { - build::SDiv(bcx, lhs, rhs, debug_loc) + bcx.sdiv(lhs, rhs) } else { - build::UDiv(bcx, lhs, rhs, debug_loc) + bcx.udiv(lhs, rhs) }, mir::BinOp::Rem => if is_float { // LLVM currently always lowers the `frem` instructions appropriate @@ -471,39 +495,47 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let llfn = declare::declare_cfn(bcx.ccx(), "fmod", fty, tcx.types.f64); if input_ty == tcx.types.f32 { - let lllhs = build::FPExt(bcx, lhs, f64t); - let llrhs = build::FPExt(bcx, rhs, f64t); - let llres = build::Call(bcx, llfn, &[lllhs, llrhs], - None, debug_loc); - build::FPTrunc(bcx, llres, Type::f32(bcx.ccx())) + let lllhs = bcx.fpext(lhs, f64t); + let llrhs = bcx.fpext(rhs, f64t); + let llres = bcx.call(llfn, &[lllhs, llrhs], None, None); + bcx.fptrunc(llres, Type::f32(bcx.ccx())) } else { - build::Call(bcx, llfn, &[lhs, rhs], - None, debug_loc) + bcx.call(llfn, &[lhs, rhs], None, None) } } else { - build::FRem(bcx, lhs, rhs, debug_loc) + bcx.frem(lhs, rhs) } } else if is_signed { - build::SRem(bcx, lhs, rhs, debug_loc) + bcx.srem(lhs, rhs) } else { - build::URem(bcx, lhs, rhs, debug_loc) + bcx.urem(lhs, rhs) }, - mir::BinOp::BitOr => build::Or(bcx, lhs, rhs, debug_loc), - mir::BinOp::BitAnd => build::And(bcx, lhs, rhs, debug_loc), - mir::BinOp::BitXor => build::Xor(bcx, lhs, rhs, debug_loc), - mir::BinOp::Shl => common::build_unchecked_lshift(bcx, - lhs, - rhs, - debug_loc), - mir::BinOp::Shr => common::build_unchecked_rshift(bcx, - input_ty, - lhs, - rhs, - debug_loc), + mir::BinOp::BitOr => bcx.or(lhs, rhs), + mir::BinOp::BitAnd => bcx.and(lhs, rhs), + mir::BinOp::BitXor => bcx.xor(lhs, rhs), + mir::BinOp::Shl => { + bcx.with_block(|bcx| { + common::build_unchecked_lshift(bcx, + lhs, + rhs, + DebugLoc::None) + }) + } + mir::BinOp::Shr => { + bcx.with_block(|bcx| { + common::build_unchecked_rshift(bcx, + input_ty, + lhs, + rhs, + DebugLoc::None) + }) + } mir::BinOp::Eq | mir::BinOp::Lt | mir::BinOp::Gt | mir::BinOp::Ne | mir::BinOp::Le | mir::BinOp::Ge => { - base::compare_scalar_types(bcx, lhs, rhs, input_ty, - op.to_hir_binop(), debug_loc) + bcx.with_block(|bcx| { + base::compare_scalar_types(bcx, lhs, rhs, input_ty, + op.to_hir_binop(), DebugLoc::None) + }) } } } diff --git a/src/librustc_trans/trans/mir/statement.rs b/src/librustc_trans/trans/mir/statement.rs index fc8885647377c..0307fd649c835 100644 --- a/src/librustc_trans/trans/mir/statement.rs +++ b/src/librustc_trans/trans/mir/statement.rs @@ -9,16 +9,16 @@ // except according to those terms. use rustc::mir::repr as mir; -use trans::common::Block; +use trans::common::BlockAndBuilder; use super::MirContext; use super::TempRef; impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn trans_statement(&mut self, - bcx: Block<'bcx, 'tcx>, + bcx: BlockAndBuilder<'bcx, 'tcx>, statement: &mir::Statement<'tcx>) - -> Block<'bcx, 'tcx> { + -> BlockAndBuilder<'bcx, 'tcx> { debug!("trans_statement(statement={:?})", statement); match statement.kind { @@ -43,7 +43,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } } _ => { - let tr_dest = self.trans_lvalue(bcx, lvalue); + let tr_dest = self.trans_lvalue(&bcx, lvalue); self.trans_rvalue(bcx, tr_dest, rvalue) } }