Skip to content

Commit

Permalink
trans: Move rust_try into the compiler
Browse files Browse the repository at this point in the history
This commit moves the IR files in the distribution, rust_try.ll,
rust_try_msvc_64.ll, and rust_try_msvc_32.ll into the compiler from the main
distribution. There's a few reasons for this change:

* LLVM changes its IR syntax from time to time, so it's very difficult to
  have these files build across many LLVM versions simultaneously. We'll likely
  want to retain this ability for quite some time into the future.
* The implementation of these files is closely tied to the compiler and runtime
  itself, so it makes sense to fold it into a location which can do more
  platform-specific checks for various implementation details (such as MSVC 32
  vs 64-bit).
* This removes LLVM as a build-time dependency of the standard library. This may
  end up becoming very useful if we move towards building the standard library
  with Cargo.

In the immediate future, however, this commit should restore compatibility with
LLVM 3.5 and 3.6.
  • Loading branch information
alexcrichton committed Jul 21, 2015
1 parent 39d4faf commit c35b2bd
Show file tree
Hide file tree
Showing 25 changed files with 519 additions and 328 deletions.
18 changes: 0 additions & 18 deletions mk/rt.mk
Expand Up @@ -54,15 +54,6 @@ NATIVE_DEPS_miniz_$(1) = miniz.c
NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \
rust_android_dummy.c
NATIVE_DEPS_rustrt_native_$(1) := arch/$$(HOST_$(1))/record_sp.S
ifeq ($$(findstring msvc,$(1)),msvc)
ifeq ($$(findstring i686,$(1)),i686)
NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_32.ll
else
NATIVE_DEPS_rustrt_native_$(1) += rust_try_msvc_64.ll
endif
else
NATIVE_DEPS_rustrt_native_$(1) += rust_try.ll
endif
NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c
NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S

Expand All @@ -76,14 +67,6 @@ NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S

RT_OUTPUT_DIR_$(1) := $(1)/rt

$$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.ll $$(MKFILE_DEPS) \
$$(LLVM_CONFIG_$$(CFG_BUILD))
@mkdir -p $$(@D)
@$$(call E, compile: $$@)
$$(Q)$$(LLC_$$(CFG_BUILD)) $$(CFG_LLC_FLAGS_$(1)) \
-filetype=obj -mtriple=$$(CFG_LLVM_TARGET_$(1)) \
-relocation-model=pic -o $$@ $$<

$$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.c $$(MKFILE_DEPS)
@mkdir -p $$(@D)
@$$(call E, compile: $$@)
Expand Down Expand Up @@ -122,7 +105,6 @@ define THIRD_PARTY_LIB
OBJS_$(2)_$(1) := $$(NATIVE_DEPS_$(2)_$(1):%=$$(RT_OUTPUT_DIR_$(1))/%)
OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.c=.o)
OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.cpp=.o)
OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.ll=.o)
OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.S=.o)
NATIVE_$(2)_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$(2))
$$(RT_OUTPUT_DIR_$(1))/$$(NATIVE_$(2)_$(1)): $$(OBJS_$(2)_$(1))
Expand Down
6 changes: 6 additions & 0 deletions src/libcore/intrinsics.rs
Expand Up @@ -602,4 +602,10 @@ extern "rust-intrinsic" {
/// Returns the value of the discriminant for the variant in 'v',
/// cast to a `u64`; if `T` has no discriminant, returns 0.
pub fn discriminant_value<T>(v: &T) -> u64;

/// Rust's "try catch" construct which invokes the function pointer `f` with
/// the data pointer `data`, returning the exception payload if an exception
/// is thrown (aka the thread panics).
#[cfg(not(stage0))]
pub fn try(f: fn(*mut u8), data: *mut u8) -> *mut u8;
}
2 changes: 2 additions & 0 deletions src/librustc/middle/lang_items.rs
Expand Up @@ -326,6 +326,8 @@ lets_do_this! {
StartFnLangItem, "start", start_fn;

EhPersonalityLangItem, "eh_personality", eh_personality;
EhPersonalityCatchLangItem, "eh_personality_catch", eh_personality_catch;
MSVCTryFilterLangItem, "msvc_try_filter", msvc_try_filter;

ExchangeHeapLangItem, "exchange_heap", exchange_heap;
OwnedBoxLangItem, "owned_box", owned_box;
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/weak_lang_items.rs
Expand Up @@ -119,7 +119,7 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
) }

weak_lang_items! {
panic_fmt, PanicFmtLangItem, rust_begin_unwind;
panic_fmt, PanicFmtLangItem, rust_begin_unwind;
stack_exhausted, StackExhaustedLangItem, rust_stack_exhausted;
eh_personality, EhPersonalityLangItem, rust_eh_personality;
}
6 changes: 4 additions & 2 deletions src/librustc_llvm/lib.rs
Expand Up @@ -134,7 +134,7 @@ pub enum DLLStorageClassTypes {
}

bitflags! {
flags Attribute : u32 {
flags Attribute : u64 {
const ZExt = 1 << 0,
const SExt = 1 << 1,
const NoReturn = 1 << 2,
Expand All @@ -161,6 +161,7 @@ bitflags! {
const ReturnsTwice = 1 << 29,
const UWTable = 1 << 30,
const NonLazyBind = 1 << 31,
const OptimizeNone = 1 << 42,
}
}

Expand Down Expand Up @@ -2193,7 +2194,8 @@ pub fn ConstFCmp(pred: RealPredicate, v1: ValueRef, v2: ValueRef) -> ValueRef {

pub fn SetFunctionAttribute(fn_: ValueRef, attr: Attribute) {
unsafe {
LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint, attr.bits() as uint64_t)
LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint,
attr.bits() as uint64_t)
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/librustc_trans/trans/build.rs
Expand Up @@ -1042,6 +1042,10 @@ pub fn LandingPad(cx: Block, ty: Type, pers_fn: ValueRef,
B(cx).landing_pad(ty, pers_fn, num_clauses, cx.fcx.llfn)
}

pub fn AddClause(cx: Block, landing_pad: ValueRef, clause: ValueRef) {
B(cx).add_clause(landing_pad, clause)
}

pub fn SetCleanup(cx: Block, landing_pad: ValueRef) {
B(cx).set_cleanup(landing_pad)
}
Expand Down
6 changes: 6 additions & 0 deletions src/librustc_trans/trans/builder.rs
Expand Up @@ -937,6 +937,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}

pub fn add_clause(&self, landing_pad: ValueRef, clause: ValueRef) {
unsafe {
llvm::LLVMAddClause(landing_pad, clause);
}
}

pub fn set_cleanup(&self, landing_pad: ValueRef) {
self.count_insn("setcleanup");
unsafe {
Expand Down
17 changes: 9 additions & 8 deletions src/librustc_trans/trans/callee.rs
Expand Up @@ -620,16 +620,17 @@ pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}, ArgVals(args), dest)
}

/// This behemoth of a function translates function calls. Unfortunately, in order to generate more
/// efficient LLVM output at -O0, it has quite a complex signature (refactoring this into two
/// functions seems like a good idea).
/// This behemoth of a function translates function calls. Unfortunately, in
/// order to generate more efficient LLVM output at -O0, it has quite a complex
/// signature (refactoring this into two functions seems like a good idea).
///
/// In particular, for lang items, it is invoked with a dest of None, and in that case the return
/// value contains the result of the fn. The lang item must not return a structural type or else
/// all heck breaks loose.
/// In particular, for lang items, it is invoked with a dest of None, and in
/// that case the return value contains the result of the fn. The lang item must
/// not return a structural type or else all heck breaks loose.
///
/// For non-lang items, `dest` is always Some, and hence the result is written into memory
/// somewhere. Nonetheless we return the actual return value of the function.
/// For non-lang items, `dest` is always Some, and hence the result is written
/// into memory somewhere. Nonetheless we return the actual return value of the
/// function.
pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
debug_loc: DebugLoc,
get_callee: F,
Expand Down
52 changes: 2 additions & 50 deletions src/librustc_trans/trans/cleanup.rs
Expand Up @@ -122,11 +122,9 @@ pub use self::Heap::*;
use llvm::{BasicBlockRef, ValueRef};
use trans::base;
use trans::build;
use trans::callee;
use trans::common;
use trans::common::{Block, FunctionContext, ExprId, NodeIdAndSpan};
use trans::common::{Block, FunctionContext, NodeIdAndSpan};
use trans::debuginfo::{DebugLoc, ToDebugLoc};
use trans::declare;
use trans::glue;
use middle::region;
use trans::type_::Type;
Expand Down Expand Up @@ -833,53 +831,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
&[Type::i8p(self.ccx), Type::i32(self.ccx)],
false);

// The exception handling personality function.
//
// If our compilation unit has the `eh_personality` lang item somewhere
// within it, then we just need to translate that. Otherwise, we're
// building an rlib which will depend on some upstream implementation of
// this function, so we just codegen a generic reference to it. We don't
// specify any of the types for the function, we just make it a symbol
// that LLVM can later use.
//
// Note that MSVC is a little special here in that we don't use the
// `eh_personality` lang item at all. Currently LLVM has support for
// both Dwarf and SEH unwind mechanisms for MSVC targets and uses the
// *name of the personality function* to decide what kind of unwind side
// tables/landing pads to emit. It looks like Dwarf is used by default,
// injecting a dependency on the `_Unwind_Resume` symbol for resuming
// an "exception", but for MSVC we want to force SEH. This means that we
// can't actually have the personality function be our standard
// `rust_eh_personality` function, but rather we wired it up to the
// CRT's custom personality function, which forces LLVM to consider
// landing pads as "landing pads for SEH".
let target = &self.ccx.sess().target.target;
let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() {
Some(def_id) if !target.options.is_like_msvc => {
callee::trans_fn_ref(pad_bcx.ccx(), def_id, ExprId(0),
pad_bcx.fcx.param_substs).val
}
_ => {
let mut personality = self.ccx.eh_personality().borrow_mut();
match *personality {
Some(llpersonality) => llpersonality,
None => {
let name = if !target.options.is_like_msvc {
"rust_eh_personality"
} else if target.arch == "x86" {
"_except_handler3"
} else {
"__C_specific_handler"
};
let fty = Type::variadic_func(&[], &Type::i32(self.ccx));
let f = declare::declare_cfn(self.ccx, name, fty,
self.ccx.tcx().types.i32);
*personality = Some(f);
f
}
}
}
};
let llpersonality = pad_bcx.fcx.eh_personality();

// The only landing pad clause will be 'cleanup'
let llretval = build::LandingPad(pad_bcx, llretty, llpersonality, 1);
Expand Down
16 changes: 6 additions & 10 deletions src/librustc_trans/trans/closure.rs
Expand Up @@ -163,11 +163,10 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc
mangle_internal_name_by_path_and_seq(path, "closure")
});

// Currently there’s only a single user of get_or_create_declaration_if_closure and it
// unconditionally defines the function, therefore we use define_* here.
let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type).unwrap_or_else(||{
ccx.sess().bug(&format!("symbol `{}` already defined", symbol));
});
// Currently there’s only a single user of
// get_or_create_declaration_if_closure and it unconditionally defines the
// function, therefore we use define_* here.
let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type);

// set an inline hint for all closures
attributes::inline(llfn, attributes::InlineAttr::Hint);
Expand Down Expand Up @@ -388,11 +387,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(

// Create the by-value helper.
let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim");
let lloncefn = declare::define_internal_rust_fn(ccx, &function_name[..], llonce_fn_ty)
.unwrap_or_else(||{
ccx.sess().bug(&format!("symbol `{}` already defined", function_name));
});

let lloncefn = declare::define_internal_rust_fn(ccx, &function_name,
llonce_fn_ty);
let sig = tcx.erase_late_bound_regions(&llonce_bare_fn_ty.sig);
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
block_arena = TypedArena::new();
Expand Down
51 changes: 51 additions & 0 deletions src/librustc_trans/trans/common.rs
Expand Up @@ -25,6 +25,7 @@ use middle::lang_items::LangItem;
use middle::subst::{self, Substs};
use trans::base;
use trans::build;
use trans::callee;
use trans::cleanup;
use trans::consts;
use trans::datum;
Expand Down Expand Up @@ -479,6 +480,56 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
type_needs_drop_given_env(self.ccx.tcx(), ty, &self.param_env)
}

pub fn eh_personality(&self) -> ValueRef {
// The exception handling personality function.
//
// If our compilation unit has the `eh_personality` lang item somewhere
// within it, then we just need to translate that. Otherwise, we're
// building an rlib which will depend on some upstream implementation of
// this function, so we just codegen a generic reference to it. We don't
// specify any of the types for the function, we just make it a symbol
// that LLVM can later use.
//
// Note that MSVC is a little special here in that we don't use the
// `eh_personality` lang item at all. Currently LLVM has support for
// both Dwarf and SEH unwind mechanisms for MSVC targets and uses the
// *name of the personality function* to decide what kind of unwind side
// tables/landing pads to emit. It looks like Dwarf is used by default,
// injecting a dependency on the `_Unwind_Resume` symbol for resuming
// an "exception", but for MSVC we want to force SEH. This means that we
// can't actually have the personality function be our standard
// `rust_eh_personality` function, but rather we wired it up to the
// CRT's custom personality function, which forces LLVM to consider
// landing pads as "landing pads for SEH".
let target = &self.ccx.sess().target.target;
match self.ccx.tcx().lang_items.eh_personality() {
Some(def_id) if !target.options.is_like_msvc => {
callee::trans_fn_ref(self.ccx, def_id, ExprId(0),
self.param_substs).val
}
_ => {
let mut personality = self.ccx.eh_personality().borrow_mut();
match *personality {
Some(llpersonality) => llpersonality,
None => {
let name = if !target.options.is_like_msvc {
"rust_eh_personality"
} else if target.arch == "x86" {
"_except_handler3"
} else {
"__C_specific_handler"
};
let fty = Type::variadic_func(&[], &Type::i32(self.ccx));
let f = declare::declare_cfn(self.ccx, name, fty,
self.ccx.tcx().types.i32);
*personality = Some(f);
f
}
}
}
}
}
}

// Basic block context. We create a block context for each basic block
Expand Down
7 changes: 7 additions & 0 deletions src/librustc_trans/trans/context.rs
Expand Up @@ -142,6 +142,7 @@ pub struct LocalCrateContext<'tcx> {
dbg_cx: Option<debuginfo::CrateDebugContext<'tcx>>,

eh_personality: RefCell<Option<ValueRef>>,
rust_try_fn: RefCell<Option<ValueRef>>,

intrinsics: RefCell<FnvHashMap<&'static str, ValueRef>>,

Expand Down Expand Up @@ -461,6 +462,7 @@ impl<'tcx> LocalCrateContext<'tcx> {
closure_vals: RefCell::new(FnvHashMap()),
dbg_cx: dbg_cx,
eh_personality: RefCell::new(None),
rust_try_fn: RefCell::new(None),
intrinsics: RefCell::new(FnvHashMap()),
n_llvm_insns: Cell::new(0),
trait_cache: RefCell::new(FnvHashMap()),
Expand Down Expand Up @@ -726,6 +728,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
&self.local.eh_personality
}

pub fn rust_try_fn<'a>(&'a self) -> &'a RefCell<Option<ValueRef>> {
&self.local.rust_try_fn
}

fn intrinsics<'a>(&'a self) -> &'a RefCell<FnvHashMap<&'static str, ValueRef>> {
&self.local.intrinsics
}
Expand Down Expand Up @@ -923,6 +929,7 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef
ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void);

ifn!("llvm.expect.i1", fn(i1, i1) -> i1);
ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32);

// Some intrinsics were introduced in later versions of LLVM, but they have
// fallbacks in libc or libm and such.
Expand Down
21 changes: 11 additions & 10 deletions src/librustc_trans/trans/declare.rs
Expand Up @@ -176,8 +176,8 @@ pub fn define_global(ccx: &CrateContext, name: &str, ty: Type) -> Option<ValueRe
/// return None if the name already has a definition associated with it. In that
/// case an error should be reported to the user, because it usually happens due
/// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes).
pub fn define_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, fn_type: Type,
output: ty::FnOutput) -> Option<ValueRef> {
pub fn define_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv,
fn_type: Type, output: ty::FnOutput) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
None
} else {
Expand Down Expand Up @@ -224,20 +224,21 @@ pub fn define_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
/// Declare a Rust function with an intention to define it.
///
/// Use this function when you intend to define a function. This function will
/// return None if the name already has a definition associated with it. In that
/// case an error should be reported to the user, because it usually happens due
/// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes).
pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> Option<ValueRef> {
/// return panic if the name already has a definition associated with it. This
/// can happen with #[no_mangle] or #[export_name], for example.
pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
name: &str,
fn_type: ty::Ty<'tcx>) -> ValueRef {
if get_defined_value(ccx, name).is_some() {
None
ccx.sess().fatal(&format!("symbol `{}` already defined", name))
} else {
Some(declare_internal_rust_fn(ccx, name, fn_type))
declare_internal_rust_fn(ccx, name, fn_type)
}
}


/// Get defined or externally defined (AvailableExternally linkage) value by name.
/// Get defined or externally defined (AvailableExternally linkage) value by
/// name.
fn get_defined_value(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
debug!("get_defined_value(name={:?})", name);
let namebuf = CString::new(name).unwrap_or_else(|_|{
Expand Down
4 changes: 1 addition & 3 deletions src/librustc_trans/trans/foreign.rs
Expand Up @@ -627,9 +627,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ccx.tcx().map.path_to_string(id),
id, t);

let llfn = declare::define_internal_rust_fn(ccx, &ps[..], t).unwrap_or_else(||{
ccx.sess().bug(&format!("symbol `{}` already defined", ps));
});
let llfn = declare::define_internal_rust_fn(ccx, &ps, t);
attributes::from_fn_attrs(ccx, attrs, llfn);
base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]);
llfn
Expand Down

0 comments on commit c35b2bd

Please sign in to comment.