From 24c1a07c729911997397b47c7fbc3fa0a657a3aa Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 11 May 2017 02:01:25 +0300 Subject: [PATCH] refactor trans::mir::block to trans all calls through the same code --- src/librustc_trans/abi.rs | 12 ++- src/librustc_trans/mir/block.rs | 139 +++++++++++++++++--------------- 2 files changed, 84 insertions(+), 67 deletions(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 9b94a3b2f23..120f201a9c8 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -11,7 +11,7 @@ use llvm::{self, ValueRef, AttributePlace}; use base; use builder::Builder; -use common::{type_is_fat_ptr, C_uint}; +use common::{instance_ty, ty_fn_sig, type_is_fat_ptr, C_uint}; use context::CrateContext; use cabi_x86; use cabi_x86_64; @@ -610,6 +610,14 @@ pub struct FnType<'tcx> { } impl<'a, 'tcx> FnType<'tcx> { + pub fn of_instance(ccx: &CrateContext<'a, 'tcx>, instance: &ty::Instance<'tcx>) + -> Self { + let fn_ty = instance_ty(ccx.shared(), &instance); + let sig = ty_fn_sig(ccx, fn_ty); + let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig); + Self::new(ccx, sig, &[]) + } + pub fn new(ccx: &CrateContext<'a, 'tcx>, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx> { @@ -631,6 +639,8 @@ pub fn new_vtable(ccx: &CrateContext<'a, 'tcx>, pub fn unadjusted(ccx: &CrateContext<'a, 'tcx>, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx> { + debug!("FnType::unadjusted({:?}, {:?})", sig, extra_args); + use self::Abi::*; let cconv = match ccx.sess().target.target.adjust_abi(sig.abi) { RustIntrinsic | PlatformIntrinsic | diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 724ff2f2134..f6c8ee0c825 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -53,7 +53,23 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock, _ => funclets[bb].as_ref(), }; + for statement in &data.statements { + bcx = self.trans_statement(bcx, statement); + } + + self.trans_terminator(bcx, bb, data.terminator(), funclet); + } + + fn trans_terminator(&mut self, + mut bcx: Builder<'a, 'tcx>, + bb: mir::BasicBlock, + terminator: &mir::Terminator<'tcx>, + funclet: Option<&Funclet>) + { + debug!("trans_terminator: {:?}", terminator); + // Create the cleanup bundle, if needed. + let tcx = bcx.tcx(); let cleanup_pad = funclet.map(|lp| lp.cleanuppad()); let cleanup_bundle = funclet.map(|l| l.bundle()); @@ -104,12 +120,53 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock, } }; - for statement in &data.statements { - bcx = self.trans_statement(bcx, statement); - } + let do_call = | + this: &mut Self, + bcx: Builder<'a, 'tcx>, + fn_ty: FnType<'tcx>, + fn_ptr: ValueRef, + llargs: &[ValueRef], + destination: Option<(ReturnDest, ty::Ty<'tcx>, mir::BasicBlock)>, + cleanup: Option + | { + if let Some(cleanup) = cleanup { + let ret_bcx = if let Some((_, _, target)) = destination { + this.blocks[target] + } else { + this.unreachable_block() + }; + let invokeret = bcx.invoke(fn_ptr, + &llargs, + ret_bcx, + llblock(this, cleanup), + cleanup_bundle); + fn_ty.apply_attrs_callsite(invokeret); + + if let Some((ret_dest, ret_ty, target)) = destination { + let ret_bcx = this.get_builder(target); + this.set_debug_loc(&ret_bcx, terminator.source_info); + let op = OperandRef { + val: Immediate(invokeret), + ty: ret_ty, + }; + this.store_return(&ret_bcx, ret_dest, &fn_ty.ret, op); + } + } else { + let llret = bcx.call(fn_ptr, &llargs, cleanup_bundle); + fn_ty.apply_attrs_callsite(llret); - let terminator = data.terminator(); - debug!("trans_block: terminator: {:?}", terminator); + if let Some((ret_dest, ret_ty, target)) = destination { + let op = OperandRef { + val: Immediate(llret), + ty: ret_ty, + }; + this.store_return(&bcx, ret_dest, &fn_ty.ret, op); + funclet_br(this, bcx, target); + } else { + bcx.unreachable(); + } + } + }; let span = terminator.source_info.span; self.set_debug_loc(&bcx, terminator.source_info); @@ -218,24 +275,16 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock, } let lvalue = self.trans_lvalue(&bcx, location); + let fn_ty = FnType::of_instance(bcx.ccx, &drop_fn); let (drop_fn, need_extra) = match ty.sty { ty::TyDynamic(..) => (meth::DESTRUCTOR.get_fn(&bcx, lvalue.llextra), false), _ => (callee::get_fn(bcx.ccx, drop_fn), lvalue.has_extra()) }; let args = &[lvalue.llval, lvalue.llextra][..1 + need_extra as usize]; - if let Some(unwind) = unwind { - bcx.invoke( - drop_fn, - args, - self.blocks[target], - llblock(self, unwind), - cleanup_bundle - ); - } else { - bcx.call(drop_fn, args, cleanup_bundle); - funclet_br(self, bcx, target); - } + do_call(self, bcx, fn_ty, drop_fn, args, + Some((ReturnDest::Nothing, tcx.mk_nil(), target)), + unwind); } mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => { @@ -342,26 +391,18 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock, // Obtain the panic entry point. let def_id = common::langcall(bcx.tcx(), Some(span), "", lang_item); let instance = ty::Instance::mono(bcx.tcx(), def_id); + let fn_ty = FnType::of_instance(bcx.ccx, &instance); let llfn = callee::get_fn(bcx.ccx, instance); // Translate the actual panic invoke/call. - if let Some(unwind) = cleanup { - bcx.invoke(llfn, - &args, - self.unreachable_block(), - llblock(self, unwind), - cleanup_bundle); - } else { - bcx.call(llfn, &args, cleanup_bundle); - bcx.unreachable(); - } + do_call(self, bcx, fn_ty, llfn, &args, None, cleanup); } mir::TerminatorKind::DropAndReplace { .. } => { - bug!("undesugared DropAndReplace in trans: {:?}", data); + bug!("undesugared DropAndReplace in trans: {:?}", terminator); } - mir::TerminatorKind::Call { ref func, ref args, ref destination, ref cleanup } => { + mir::TerminatorKind::Call { ref func, ref args, ref destination, cleanup } => { // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. let callee = self.trans_operand(&bcx, func); @@ -514,43 +555,9 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock, _ => span_bug!(span, "no llfn for call"), }; - // Many different ways to call a function handled here - if let &Some(cleanup) = cleanup { - let ret_bcx = if let Some((_, target)) = *destination { - self.blocks[target] - } else { - self.unreachable_block() - }; - let invokeret = bcx.invoke(fn_ptr, - &llargs, - ret_bcx, - llblock(self, cleanup), - cleanup_bundle); - fn_ty.apply_attrs_callsite(invokeret); - - if let Some((_, target)) = *destination { - let ret_bcx = self.get_builder(target); - self.set_debug_loc(&ret_bcx, terminator.source_info); - let op = OperandRef { - val: Immediate(invokeret), - ty: sig.output(), - }; - self.store_return(&ret_bcx, ret_dest, &fn_ty.ret, op); - } - } else { - let llret = bcx.call(fn_ptr, &llargs, cleanup_bundle); - fn_ty.apply_attrs_callsite(llret); - if let Some((_, target)) = *destination { - let op = OperandRef { - val: Immediate(llret), - ty: sig.output(), - }; - self.store_return(&bcx, ret_dest, &fn_ty.ret, op); - funclet_br(self, bcx, target); - } else { - bcx.unreachable(); - } - } + do_call(self, bcx, fn_ty, fn_ptr, &llargs, + destination.as_ref().map(|&(_, target)| (ret_dest, sig.output(), target)), + cleanup); } } } -- 2.44.0