[eddyb/rebase cleanup] abstracted Funclet

This commit is contained in:
Eduard-Mihai Burtescu 2018-11-13 12:51:42 +02:00
parent 566fa4d003
commit 35b40f51fb
9 changed files with 59 additions and 86 deletions

View file

@ -9,10 +9,10 @@
// except according to those terms.
use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect};
use llvm::{self, False, OperandBundleDef, BasicBlock};
use common;
use llvm::{self, False, BasicBlock};
use rustc_codegen_utils::common::{IntPredicate, TypeKind, RealPredicate};
use rustc_codegen_utils;
use common::Funclet;
use context::CodegenCx;
use type_::Type;
use type_of::LayoutLlvmExt;
@ -66,6 +66,7 @@ impl BackendTypes for Builder<'_, 'll, 'tcx> {
type BasicBlock = <CodegenCx<'ll, 'tcx> as BackendTypes>::BasicBlock;
type Type = <CodegenCx<'ll, 'tcx> as BackendTypes>::Type;
type Context = <CodegenCx<'ll, 'tcx> as BackendTypes>::Context;
type Funclet = <CodegenCx<'ll, 'tcx> as BackendTypes>::Funclet;
type DIScope = <CodegenCx<'ll, 'tcx> as BackendTypes>::DIScope;
}
@ -218,12 +219,14 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}
}
fn invoke(&self,
fn invoke(
&self,
llfn: &'ll Value,
args: &[&'ll Value],
then: &'ll BasicBlock,
catch: &'ll BasicBlock,
funclet: Option<&common::Funclet<&'ll Value>>) -> &'ll Value {
funclet: Option<&Funclet<'ll>>,
) -> &'ll Value {
self.count_insn("invoke");
debug!("Invoke {:?} with args ({:?})",
@ -232,7 +235,6 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
let args = self.check_call("invoke", llfn, args);
let bundle = funclet.map(|funclet| funclet.bundle());
let bundle = bundle.map(OperandBundleDef::from_generic);
let bundle = bundle.as_ref().map(|b| &*b.raw);
unsafe {
@ -1123,7 +1125,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
fn cleanup_pad(&self,
parent: Option<&'ll Value>,
args: &[&'ll Value]) -> &'ll Value {
args: &[&'ll Value]) -> Funclet<'ll> {
self.count_insn("cleanuppad");
let name = const_cstr!("cleanuppad");
let ret = unsafe {
@ -1133,23 +1135,23 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
args.as_ptr(),
name.as_ptr())
};
ret.expect("LLVM does not have support for cleanuppad")
Funclet::new(ret.expect("LLVM does not have support for cleanuppad"))
}
fn cleanup_ret(
&self, cleanup: &'ll Value,
&self, funclet: &Funclet<'ll>,
unwind: Option<&'ll BasicBlock>,
) -> &'ll Value {
self.count_insn("cleanupret");
let ret = unsafe {
llvm::LLVMRustBuildCleanupRet(self.llbuilder, cleanup, unwind)
llvm::LLVMRustBuildCleanupRet(self.llbuilder, funclet.cleanuppad(), unwind)
};
ret.expect("LLVM does not have support for cleanupret")
}
fn catch_pad(&self,
parent: &'ll Value,
args: &[&'ll Value]) -> &'ll Value {
args: &[&'ll Value]) -> Funclet<'ll> {
self.count_insn("catchpad");
let name = const_cstr!("catchpad");
let ret = unsafe {
@ -1157,13 +1159,13 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
args.len() as c_uint, args.as_ptr(),
name.as_ptr())
};
ret.expect("LLVM does not have support for catchpad")
Funclet::new(ret.expect("LLVM does not have support for catchpad"))
}
fn catch_ret(&self, pad: &'ll Value, unwind: &'ll BasicBlock) -> &'ll Value {
fn catch_ret(&self, funclet: &Funclet<'ll>, unwind: &'ll BasicBlock) -> &'ll Value {
self.count_insn("catchret");
let ret = unsafe {
llvm::LLVMRustBuildCatchRet(self.llbuilder, pad, unwind)
llvm::LLVMRustBuildCatchRet(self.llbuilder, funclet.cleanuppad(), unwind)
};
ret.expect("LLVM does not have support for catchret")
}
@ -1356,8 +1358,12 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
self.call(lifetime_intrinsic, &[self.cx.const_u64(size), ptr], None);
}
fn call(&self, llfn: &'ll Value, args: &[&'ll Value],
funclet: Option<&common::Funclet<&'ll Value>>) -> &'ll Value {
fn call(
&self,
llfn: &'ll Value,
args: &[&'ll Value],
funclet: Option<&Funclet<'ll>>,
) -> &'ll Value {
self.count_insn("call");
debug!("Call {:?} with args ({:?})",
@ -1366,7 +1372,6 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
let args = self.check_call("call", llfn, args);
let bundle = funclet.map(|funclet| funclet.bundle());
let bundle = bundle.map(OperandBundleDef::from_generic);
let bundle = bundle.as_ref().map(|b| &*b.raw);
unsafe {

View file

@ -12,7 +12,7 @@
//! Code that is useful in various codegen modules.
use llvm::{self, True, False, Bool, BasicBlock};
use llvm::{self, True, False, Bool, BasicBlock, OperandBundleDef};
use rustc::hir::def_id::DefId;
use rustc::middle::lang_items::LangItem;
use abi;
@ -23,7 +23,7 @@ use type_of::LayoutLlvmExt;
use value::Value;
use interfaces::*;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::{Ty, TyCtxt};
use rustc::ty::layout::{HasDataLayout, LayoutOf, self, TyLayout, Size};
use rustc::mir::interpret::{Scalar, AllocType, Allocation};
use rustc::hir;
@ -35,36 +35,10 @@ use libc::{c_uint, c_char};
use syntax::symbol::LocalInternedString;
use syntax::ast::Mutability;
use syntax_pos::{Span, DUMMY_SP};
use syntax_pos::Span;
pub use context::CodegenCx;
pub fn type_needs_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
ty.needs_drop(tcx, ty::ParamEnv::reveal_all())
}
pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
ty.is_sized(tcx.at(DUMMY_SP), ty::ParamEnv::reveal_all())
}
pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
ty.is_freeze(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP)
}
pub struct OperandBundleDef<'a, V> {
pub name: &'a str,
pub val: V
}
impl<'a, V> OperandBundleDef<'a, V> {
pub fn new(name: &'a str, val: V) -> Self {
OperandBundleDef {
name,
val
}
}
}
/*
* A note on nomenclature of linking: "extern", "foreign", and "upcall".
*
@ -105,24 +79,24 @@ impl<'a, V> OperandBundleDef<'a, V> {
/// When inside of a landing pad, each function call in LLVM IR needs to be
/// annotated with which landing pad it's a part of. This is accomplished via
/// the `OperandBundleDef` value created for MSVC landing pads.
pub struct Funclet<'a, V> {
cleanuppad: V,
operand: OperandBundleDef<'a, V>,
pub struct Funclet<'ll> {
cleanuppad: &'ll Value,
operand: OperandBundleDef<'ll>,
}
impl<'a, V: CodegenObject> Funclet<'a, V> {
pub fn new(cleanuppad: V) -> Self {
impl Funclet<'ll> {
pub fn new(cleanuppad: &'ll Value) -> Self {
Funclet {
cleanuppad,
operand: OperandBundleDef::new("funclet", cleanuppad),
operand: OperandBundleDef::new("funclet", &[cleanuppad]),
}
}
pub fn cleanuppad(&self) -> V {
pub fn cleanuppad(&self) -> &'ll Value {
self.cleanuppad
}
pub fn bundle(&self) -> &OperandBundleDef<'a, V> {
pub fn bundle(&self) -> &OperandBundleDef<'ll> {
&self.operand
}
}
@ -132,6 +106,7 @@ impl BackendTypes for CodegenCx<'ll, 'tcx> {
type BasicBlock = &'ll BasicBlock;
type Type = &'ll Type;
type Context = &'ll llvm::Context;
type Funclet = Funclet<'ll>;
type DIScope = &'ll llvm::debuginfo::DIScope;
}

View file

@ -28,6 +28,7 @@ pub trait BackendTypes {
type BasicBlock: Copy;
type Type: CodegenObject;
type Context;
type Funclet;
type DIScope: Copy;
}

View file

@ -15,7 +15,6 @@ use super::intrinsic::IntrinsicCallMethods;
use super::type_::ArgTypeMethods;
use super::HasCodegen;
use builder::MemFlags;
use common::*;
use libc::c_char;
use mir::operand::OperandRef;
use mir::place::PlaceRef;
@ -58,7 +57,7 @@ pub trait BuilderMethods<'a, 'tcx: 'a>:
args: &[Self::Value],
then: Self::BasicBlock,
catch: Self::BasicBlock,
funclet: Option<&Funclet<Self::Value>>,
funclet: Option<&Self::Funclet>,
) -> Self::Value;
fn unreachable(&self);
fn add(&self, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
@ -213,10 +212,10 @@ pub trait BuilderMethods<'a, 'tcx: 'a>:
fn add_clause(&self, landing_pad: Self::Value, clause: Self::Value);
fn set_cleanup(&self, landing_pad: Self::Value);
fn resume(&self, exn: Self::Value) -> Self::Value;
fn cleanup_pad(&self, parent: Option<Self::Value>, args: &[Self::Value]) -> Self::Value;
fn cleanup_ret(&self, cleanup: Self::Value, unwind: Option<Self::BasicBlock>) -> Self::Value;
fn catch_pad(&self, parent: Self::Value, args: &[Self::Value]) -> Self::Value;
fn catch_ret(&self, pad: Self::Value, unwind: Self::BasicBlock) -> Self::Value;
fn cleanup_pad(&self, parent: Option<Self::Value>, args: &[Self::Value]) -> Self::Funclet;
fn cleanup_ret(&self, funclet: &Self::Funclet, unwind: Option<Self::BasicBlock>) -> Self::Value;
fn catch_pad(&self, parent: Self::Value, args: &[Self::Value]) -> Self::Funclet;
fn catch_ret(&self, funclet: &Self::Funclet, unwind: Self::BasicBlock) -> Self::Value;
fn catch_switch(
&self,
parent: Option<Self::Value>,
@ -276,7 +275,7 @@ pub trait BuilderMethods<'a, 'tcx: 'a>:
&self,
llfn: Self::Value,
args: &[Self::Value],
funclet: Option<&Funclet<Self::Value>>,
funclet: Option<&Self::Funclet>,
) -> Self::Value;
fn zext(&self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;

View file

@ -72,6 +72,7 @@ pub trait HasCodegen<'tcx>: Backend<'tcx> {
BasicBlock = Self::BasicBlock,
Type = Self::Type,
Context = Self::Context,
Funclet = Self::Funclet,
DIScope = Self::DIScope,
>;
}

View file

@ -894,7 +894,7 @@ fn codegen_msvc_try(
Some(did) => cx.get_static(did),
None => bug!("msvc_try_filter not defined"),
};
let tok = catchpad.catch_pad(cs, &[tydesc, cx.const_i32(0), slot]);
let funclet = catchpad.catch_pad(cs, &[tydesc, cx.const_i32(0), slot]);
let addr = catchpad.load(slot, ptr_align);
let i64_align = bx.tcx().data_layout.i64_align;
@ -904,7 +904,7 @@ fn codegen_msvc_try(
let local_ptr = catchpad.bitcast(local_ptr, i64p);
catchpad.store(arg1, local_ptr, i64_align);
catchpad.store(arg2, catchpad.inbounds_gep(local_ptr, &[val1]), i64_align);
catchpad.catch_ret(tok, caught.llbb());
catchpad.catch_ret(&funclet, caught.llbb());
caught.ret(cx.const_i32(1));
});

View file

@ -28,7 +28,6 @@ use std::ffi::CStr;
use std::cell::RefCell;
use libc::{self, c_uint, c_char, size_t};
use rustc_data_structures::small_c_str::SmallCStr;
use common;
pub mod archive_ro;
pub mod diagnostic;
@ -272,10 +271,6 @@ impl OperandBundleDef<'a> {
};
OperandBundleDef { raw: def }
}
pub fn from_generic(bundle: &common::OperandBundleDef<'a, &'a Value>) -> Self {
Self::new(bundle.name, &[bundle.val])
}
}
impl Drop for OperandBundleDef<'a> {

View file

@ -17,7 +17,7 @@ use abi::{Abi, FnType, PassMode};
use rustc_target::abi::call::ArgType;
use base;
use builder::MemFlags;
use common::{self, Funclet};
use common;
use rustc_codegen_utils::common::IntPredicate;
use meth;
use monomorphize;
@ -67,7 +67,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
funclet_bb: Option<mir::BasicBlock>
) -> impl for<'b> Fn(
&'b FunctionCx<'a, 'tcx, Bx>,
) -> Option<&'b Funclet<'static, Bx::Value>> {
) -> Option<&'b Bx::Funclet> {
move |this| {
match funclet_bb {
Some(funclet_bb) => this.funclets[funclet_bb].as_ref(),
@ -77,8 +77,6 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
let funclet = funclet_closure_factory(funclet_bb);
let cleanup_pad = |this: &Self| funclet(this).map(|lp| lp.cleanuppad());
let lltarget = |this: &mut Self, target: mir::BasicBlock| {
let lltarget = this.blocks[target];
let target_funclet = this.cleanup_kinds[target].funclet_bb(target);
@ -106,7 +104,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
debug!("llblock: creating cleanup trampoline for {:?}", target);
let name = &format!("{:?}_cleanup_trampoline_{:?}", bb, target);
let trampoline = this.new_block(name);
trampoline.cleanup_ret(cleanup_pad(this).unwrap(), Some(lltarget));
trampoline.cleanup_ret(funclet(this).unwrap(), Some(lltarget));
trampoline.llbb()
} else {
lltarget
@ -119,7 +117,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if is_cleanupret {
// micro-optimization: generate a `ret` rather than a jump
// to a trampoline.
bx.cleanup_ret(cleanup_pad(this).unwrap(), Some(lltarget));
bx.cleanup_ret(funclet(this).unwrap(), Some(lltarget));
} else {
bx.br(lltarget);
}
@ -175,8 +173,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.set_debug_loc(&bx, terminator.source_info);
match terminator.kind {
mir::TerminatorKind::Resume => {
if let Some(cleanup_pad) = cleanup_pad(self) {
bx.cleanup_ret(cleanup_pad, None);
if let Some(funclet) = funclet(self) {
bx.cleanup_ret(funclet, None);
} else {
let slot = self.get_personality_slot(&bx);
let lp0 = bx.load_operand(slot.project_field(&bx, 0)).immediate();

View file

@ -18,7 +18,6 @@ use rustc::ty::subst::Substs;
use rustc::session::config::DebugInfo;
use base;
use debuginfo::{self, VariableAccess, VariableKind, FunctionDebugContext};
use common::Funclet;
use monomorphize::Instance;
use abi::{FnType, PassMode};
use interfaces::*;
@ -70,7 +69,7 @@ pub struct FunctionCx<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> {
/// When targeting MSVC, this stores the cleanup info for each funclet
/// BB. This is initialized as we compute the funclets' head block in RPO.
funclets: IndexVec<mir::BasicBlock, Option<Funclet<'static, Bx::Value>>>,
funclets: IndexVec<mir::BasicBlock, Option<Bx::Funclet>>,
/// This stores the landing-pad block for a given BB, computed lazily on GNU
/// and eagerly on MSVC.
@ -372,7 +371,7 @@ fn create_funclets<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
cleanup_kinds: &IndexVec<mir::BasicBlock, CleanupKind>,
block_bxs: &IndexVec<mir::BasicBlock, Bx::BasicBlock>)
-> (IndexVec<mir::BasicBlock, Option<Bx::BasicBlock>>,
IndexVec<mir::BasicBlock, Option<Funclet<'static, Bx::Value>>>)
IndexVec<mir::BasicBlock, Option<Bx::Funclet>>)
{
block_bxs.iter_enumerated().zip(cleanup_kinds).map(|((bb, &llbb), cleanup_kind)| {
match *cleanup_kind {
@ -380,7 +379,7 @@ fn create_funclets<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
_ => return (None, None)
}
let cleanup;
let funclet;
let ret_llbb;
match mir[bb].terminator.as_ref().map(|t| &t.kind) {
// This is a basic block that we're aborting the program for,
@ -417,18 +416,18 @@ fn create_funclets<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
// represents that this is a catch-all block.
let null = bx.cx().const_null(bx.cx().type_i8p());
let sixty_four = bx.cx().const_i32(64);
cleanup = cp_bx.catch_pad(cs, &[null, sixty_four, null]);
funclet = cp_bx.catch_pad(cs, &[null, sixty_four, null]);
cp_bx.br(llbb);
}
_ => {
let cleanup_bx = bx.build_sibling_block(&format!("funclet_{:?}", bb));
ret_llbb = cleanup_bx.llbb();
cleanup = cleanup_bx.cleanup_pad(None, &[]);
funclet = cleanup_bx.cleanup_pad(None, &[]);
cleanup_bx.br(llbb);
}
};
(Some(ret_llbb), Some(Funclet::new(cleanup)))
(Some(ret_llbb), Some(funclet))
}).unzip()
}