Skip to content

Commit

Permalink
Auto merge of #30448 - alexcrichton:llvmup, r=nikomatsakis
Browse files Browse the repository at this point in the history
These commits perform a few high-level changes with the goal of enabling i686 MSVC unwinding:

* LLVM is upgraded to pick up the new exception handling instructions and intrinsics for MSVC. This puts us somewhere along the 3.8 branch, but we should still be compatible with LLVM 3.7 for non-MSVC targets.
* All unwinding for MSVC targets (both 32 and 64-bit) are implemented in terms of this new LLVM support. I would like to also extend this to Windows GNU targets to drop the runtime dependencies we have on MinGW, but I'd like to land this first.
* Some tests were fixed up for i686 MSVC here and there where necessary. The full test suite should be passing now for that target.

In terms of landing this I plan to have this go through first, then verify that i686 MSVC works, then I'll enable `make check` on the bots for that target instead of just `make` as-is today.

Closes #25869
  • Loading branch information
bors committed Jan 30, 2016
2 parents 074f49a + 58f1b9c commit 303892e
Show file tree
Hide file tree
Showing 47 changed files with 1,356 additions and 567 deletions.
2 changes: 2 additions & 0 deletions mk/tests.mk
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,8 @@ $(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(3)))
$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(3)))
$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
export MSVC_LIB := "$$(CFG_MSVC_LIB_$$(HOST_$(3)))"
$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
$(S)src/test/run-make/%/Makefile \
$$(CSREQ$(1)_T_$(2)_H_$(3))
Expand Down
12 changes: 10 additions & 2 deletions src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,15 @@ extern "rust-intrinsic" {
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).
/// the data pointer `data`.
///
/// The third pointer is a target-specific data pointer which is filled in
/// with the specifics of the exception that occurred. For examples on Unix
/// platforms this is a `*mut *mut T` which is filled in by the compiler and
/// on MSVC it's `*mut [usize; 2]`. For more information see the compiler's
/// source as well as std's catch implementation.
#[cfg(not(stage0))]
pub fn try(f: fn(*mut u8), data: *mut u8, local_ptr: *mut u8) -> i32;
#[cfg(stage0)]
pub fn try(f: fn(*mut u8), data: *mut u8) -> *mut u8;
}
1 change: 0 additions & 1 deletion src/librustc_back/target/x86_64_pc_windows_msvc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ use target::Target;
pub fn target() -> Target {
let mut base = super::windows_msvc_base::opts();
base.cpu = "x86-64".to_string();
base.custom_unwind_resume = true;

Target {
llvm_target: "x86_64-pc-windows-msvc".to_string(),
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_llvm/archive_ro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,14 @@ impl Drop for ArchiveRO {
}

impl<'a> Iterator for Iter<'a> {
type Item = Child<'a>;
type Item = Result<Child<'a>, String>;

fn next(&mut self) -> Option<Child<'a>> {
fn next(&mut self) -> Option<Result<Child<'a>, String>> {
let ptr = unsafe { ::LLVMRustArchiveIteratorNext(self.ptr) };
if ptr.is_null() {
None
::last_error().map(Err)
} else {
Some(Child { ptr: ptr, _data: marker::PhantomData })
Some(Ok(Child { ptr: ptr, _data: marker::PhantomData }))
}
}
}
Expand Down
108 changes: 93 additions & 15 deletions src/librustc_llvm/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub use self::DiagnosticSeverity::*;
pub use self::Linkage::*;
pub use self::DLLStorageClassTypes::*;

use std::ffi::CString;
use std::ffi::{CString, CStr};
use std::cell::RefCell;
use std::slice;
use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char};
Expand Down Expand Up @@ -544,6 +544,9 @@ pub type SMDiagnosticRef = *mut SMDiagnostic_opaque;
#[allow(missing_copy_implementations)]
pub enum RustArchiveMember_opaque {}
pub type RustArchiveMemberRef = *mut RustArchiveMember_opaque;
#[allow(missing_copy_implementations)]
pub enum OperandBundleDef_opaque {}
pub type OperandBundleDefRef = *mut OperandBundleDef_opaque;

pub type DiagnosticHandler = unsafe extern "C" fn(DiagnosticInfoRef, *mut c_void);
pub type InlineAsmDiagHandler = unsafe extern "C" fn(SMDiagnosticRef, *const c_void, c_uint);
Expand Down Expand Up @@ -1149,14 +1152,15 @@ extern {
Addr: ValueRef,
NumDests: c_uint)
-> ValueRef;
pub fn LLVMBuildInvoke(B: BuilderRef,
Fn: ValueRef,
Args: *const ValueRef,
NumArgs: c_uint,
Then: BasicBlockRef,
Catch: BasicBlockRef,
Name: *const c_char)
-> ValueRef;
pub fn LLVMRustBuildInvoke(B: BuilderRef,
Fn: ValueRef,
Args: *const ValueRef,
NumArgs: c_uint,
Then: BasicBlockRef,
Catch: BasicBlockRef,
Bundle: OperandBundleDefRef,
Name: *const c_char)
-> ValueRef;
pub fn LLVMRustBuildLandingPad(B: BuilderRef,
Ty: TypeRef,
PersFn: ValueRef,
Expand All @@ -1167,6 +1171,31 @@ extern {
pub fn LLVMBuildResume(B: BuilderRef, Exn: ValueRef) -> ValueRef;
pub fn LLVMBuildUnreachable(B: BuilderRef) -> ValueRef;

pub fn LLVMRustBuildCleanupPad(B: BuilderRef,
ParentPad: ValueRef,
ArgCnt: c_uint,
Args: *const ValueRef,
Name: *const c_char) -> ValueRef;
pub fn LLVMRustBuildCleanupRet(B: BuilderRef,
CleanupPad: ValueRef,
UnwindBB: BasicBlockRef) -> ValueRef;
pub fn LLVMRustBuildCatchPad(B: BuilderRef,
ParentPad: ValueRef,
ArgCnt: c_uint,
Args: *const ValueRef,
Name: *const c_char) -> ValueRef;
pub fn LLVMRustBuildCatchRet(B: BuilderRef,
Pad: ValueRef,
BB: BasicBlockRef) -> ValueRef;
pub fn LLVMRustBuildCatchSwitch(Builder: BuilderRef,
ParentPad: ValueRef,
BB: BasicBlockRef,
NumHandlers: c_uint,
Name: *const c_char) -> ValueRef;
pub fn LLVMRustAddHandler(CatchSwitch: ValueRef,
Handler: BasicBlockRef);
pub fn LLVMRustSetPersonalityFn(B: BuilderRef, Pers: ValueRef);

/* Add a case to the switch instruction */
pub fn LLVMAddCase(Switch: ValueRef,
OnVal: ValueRef,
Expand Down Expand Up @@ -1476,12 +1505,13 @@ extern {
/* Miscellaneous instructions */
pub fn LLVMBuildPhi(B: BuilderRef, Ty: TypeRef, Name: *const c_char)
-> ValueRef;
pub fn LLVMBuildCall(B: BuilderRef,
Fn: ValueRef,
Args: *const ValueRef,
NumArgs: c_uint,
Name: *const c_char)
-> ValueRef;
pub fn LLVMRustBuildCall(B: BuilderRef,
Fn: ValueRef,
Args: *const ValueRef,
NumArgs: c_uint,
Bundle: OperandBundleDefRef,
Name: *const c_char)
-> ValueRef;
pub fn LLVMBuildSelect(B: BuilderRef,
If: ValueRef,
Then: ValueRef,
Expand Down Expand Up @@ -2126,6 +2156,12 @@ extern {
pub fn LLVMRustSetDataLayoutFromTargetMachine(M: ModuleRef,
TM: TargetMachineRef);
pub fn LLVMRustGetModuleDataLayout(M: ModuleRef) -> TargetDataRef;

pub fn LLVMRustBuildOperandBundleDef(Name: *const c_char,
Inputs: *const ValueRef,
NumInputs: c_uint)
-> OperandBundleDefRef;
pub fn LLVMRustFreeOperandBundleDef(Bundle: OperandBundleDefRef);
}

#[cfg(have_component_x86)]
Expand Down Expand Up @@ -2404,6 +2440,48 @@ pub fn initialize_available_targets() {
init_pnacl();
}

pub fn last_error() -> Option<String> {
unsafe {
let cstr = LLVMRustGetLastError();
if cstr.is_null() {
None
} else {
let err = CStr::from_ptr(cstr).to_bytes();
let err = String::from_utf8_lossy(err).to_string();
libc::free(cstr as *mut _);
Some(err)
}
}
}

pub struct OperandBundleDef {
inner: OperandBundleDefRef,
}

impl OperandBundleDef {
pub fn new(name: &str, vals: &[ValueRef]) -> OperandBundleDef {
let name = CString::new(name).unwrap();
let def = unsafe {
LLVMRustBuildOperandBundleDef(name.as_ptr(),
vals.as_ptr(),
vals.len() as c_uint)
};
OperandBundleDef { inner: def }
}

pub fn raw(&self) -> OperandBundleDefRef {
self.inner
}
}

impl Drop for OperandBundleDef {
fn drop(&mut self) {
unsafe {
LLVMRustFreeOperandBundleDef(self.inner);
}
}
}

// The module containing the native LLVM dependencies, generated by the build system
// Note that this must come after the rustllvm extern declaration so that
// parts of LLVM that rustllvm depends on aren't thrown away by the linker.
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_metadata/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,7 @@ pub fn note_crate_name(err: &mut DiagnosticBuilder, name: &str) {
impl ArchiveMetadata {
fn new(ar: ArchiveRO) -> Option<ArchiveMetadata> {
let data = {
let section = ar.iter().find(|sect| {
let section = ar.iter().filter_map(|s| s.ok()).find(|sect| {
sect.name() == Some(METADATA_FILENAME)
});
match section {
Expand Down
37 changes: 32 additions & 5 deletions src/librustc_trans/back/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ impl<'a> ArchiveBuilder<'a> {
}
let archive = self.src_archive.as_ref().unwrap().as_ref().unwrap();
let ret = archive.iter()
.filter_map(|child| child.ok())
.filter(is_relevant_child)
.filter_map(|child| child.name())
.filter(|name| !self.removals.iter().any(|x| x == name))
Expand Down Expand Up @@ -332,9 +333,15 @@ impl<'a> ArchiveBuilder<'a> {
// We skip any files explicitly desired for skipping, and we also skip
// all SYMDEF files as these are just magical placeholders which get
// re-created when we make a new archive anyway.
for file in archive.iter().filter(is_relevant_child) {
for file in archive.iter() {
let file = try!(file.map_err(string_to_io_error));
if !is_relevant_child(&file) {
continue
}
let filename = file.name().unwrap();
if skip(filename) { continue }
if skip(filename) {
continue
}
let filename = Path::new(filename).file_name().unwrap()
.to_str().unwrap();

Expand Down Expand Up @@ -448,6 +455,7 @@ impl<'a> ArchiveBuilder<'a> {
unsafe {
if let Some(archive) = self.src_archive() {
for child in archive.iter() {
let child = try!(child.map_err(string_to_io_error));
let child_name = match child.name() {
Some(s) => s,
None => continue,
Expand Down Expand Up @@ -475,10 +483,25 @@ impl<'a> ArchiveBuilder<'a> {
strings.push(name);
}
Addition::Archive { archive, archive_name: _, mut skip } => {
for child in archive.iter().filter(is_relevant_child) {
for child in archive.iter() {
let child = try!(child.map_err(string_to_io_error));
if !is_relevant_child(&child) {
continue
}
let child_name = child.name().unwrap();
if skip(child_name) { continue }

if skip(child_name) {
continue
}

// It appears that LLVM's archive writer is a little
// buggy if the name we pass down isn't just the
// filename component, so chop that off here and
// pass it in.
//
// See LLVM bug 25877 for more info.
let child_name = Path::new(child_name)
.file_name().unwrap()
.to_str().unwrap();
let name = try!(CString::new(child_name));
let m = llvm::LLVMRustArchiveMemberNew(ptr::null(),
name.as_ptr(),
Expand Down Expand Up @@ -517,3 +540,7 @@ impl<'a> ArchiveBuilder<'a> {
}
}
}

fn string_to_io_error(s: String) -> io::Error {
io::Error::new(io::ErrorKind::Other, format!("bad archive: {}", s))
}
2 changes: 1 addition & 1 deletion src/librustc_trans/back/lto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
link::each_linked_rlib(sess, &mut |_, path| {
let archive = ArchiveRO::open(&path).expect("wanted an rlib");
let bytecodes = archive.iter().filter_map(|child| {
child.name().map(|name| (name, child))
child.ok().and_then(|c| c.name().map(|name| (name, c)))
}).filter(|&(name, _)| name.ends_with("bytecode.deflate"));
for (name, data) in bytecodes {
let bc_encoded = data.data();
Expand Down
16 changes: 4 additions & 12 deletions src/librustc_trans/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,16 @@ use std::collections::HashMap;
use std::ffi::{CStr, CString};
use std::fs;
use std::path::{Path, PathBuf};
use std::ptr;
use std::str;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::channel;
use std::thread;
use libc::{self, c_uint, c_int, c_void};
use libc::{c_uint, c_int, c_void};

pub fn llvm_err(handler: &errors::Handler, msg: String) -> ! {
unsafe {
let cstr = llvm::LLVMRustGetLastError();
if cstr == ptr::null() {
panic!(handler.fatal(&msg[..]));
} else {
let err = CStr::from_ptr(cstr).to_bytes();
let err = String::from_utf8_lossy(err).to_string();
libc::free(cstr as *mut _);
panic!(handler.fatal(&format!("{}: {}", &msg[..], &err[..])));
}
match llvm::last_error() {
Some(err) => panic!(handler.fatal(&format!("{}: {}", msg, err))),
None => panic!(handler.fatal(&msg)),
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/librustc_trans/trans/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1271,7 +1271,8 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
};
}
Variant(_, ref repr, _, _) => {
let (the_kind, val_opt) = adt::trans_switch(bcx, &**repr, val.val);
let (the_kind, val_opt) = adt::trans_switch(bcx, &repr,
val.val, true);
kind = the_kind;
if let Some(tval) = val_opt { test_val = tval; }
}
Expand Down
Loading

0 comments on commit 303892e

Please sign in to comment.