Separating the back folder between backend-agnostic and LLVM-specific code

This commit is contained in:
Denis Merigoux 2018-10-23 17:01:35 +02:00 committed by Eduard-Mihai Burtescu
parent b25b804013
commit b9e5cf99a9
23 changed files with 2725 additions and 2468 deletions

View File

@ -2129,6 +2129,12 @@ dependencies = [
[[package]]
name = "rustc_codegen_ssa"
version = "0.0.0"
dependencies = [
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc_codegen_utils"
@ -2137,13 +2143,11 @@ dependencies = [
"flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc_allocator 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_incremental 0.0.0",
"rustc_metadata 0.0.0",
"rustc_mir 0.0.0",
"rustc_target 0.0.0",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]

View File

@ -18,6 +18,7 @@ use std::ptr;
use std::str;
use back::bytecode::RLIB_BYTECODE_EXTENSION;
use rustc_codegen_ssa::back::archive::find_library;
use libc;
use llvm::archive_ro::{ArchiveRO, Child};
use llvm::{self, ArchiveKind};
@ -52,7 +53,6 @@ enum Addition {
},
}
fn is_relevant_child(c: &Child) -> bool {
match c.name() {
Some(name) => !name.contains("SYMDEF"),
@ -107,7 +107,7 @@ impl<'a> ArchiveBuilder<'a> {
/// Adds all of the contents of a native library to this archive. This will
/// search in the relevant locations for a library named `name`.
pub fn add_native_library(&mut self, name: &str) {
let location = ::rustc_codegen_utils::find_library(name, &self.config.lib_search_paths,
let location = find_library(name, &self.config.lib_search_paths,
self.config.sess);
self.add_archive(&location, |_| false).unwrap_or_else(|e| {
self.config.sess.fatal(&format!("failed to add native library {}: {}",

View File

@ -9,9 +9,12 @@
// except according to those terms.
use back::wasm;
use cc::windows_registry;
use super::archive::{ArchiveBuilder, ArchiveConfig};
use super::bytecode::RLIB_BYTECODE_EXTENSION;
use rustc_codegen_ssa::back::linker::Linker;
use rustc_codegen_ssa::back::link::{remove, ignored_for_lto, each_linked_rlib, linker_and_flavor,
get_linker};
use rustc_codegen_ssa::back::command::Command;
use super::rpath::RPathConfig;
use super::rpath;
use metadata::METADATA_FILENAME;
@ -20,18 +23,15 @@ use rustc::session::config::{RUST_CGU_EXT, Lto};
use rustc::session::filesearch;
use rustc::session::search_paths::PathKind;
use rustc::session::Session;
use rustc::middle::cstore::{NativeLibrary, LibSource, NativeLibraryKind};
use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind};
use rustc::middle::dependency_format::Linkage;
use rustc_codegen_ssa::CrateInfo;
use CodegenResults;
use rustc_codegen_ssa::CodegenResults;
use rustc::util::common::time;
use rustc_fs_util::fix_windows_verbatim_for_gcc;
use rustc::hir::def_id::CrateNum;
use tempfile::{Builder as TempFileBuilder, TempDir};
use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor};
use rustc_data_structures::fx::FxHashSet;
use rustc_codegen_utils::linker::Linker;
use rustc_codegen_utils::command::Command;
use context::get_reloc_model;
use llvm;
@ -51,69 +51,6 @@ pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default
invalid_output_for_target, filename_for_metadata,
out_filename, check_file_is_writeable};
// The third parameter is for env vars, used on windows to set up the
// path for MSVC to find its DLLs, and gcc to find its bundled
// toolchain
pub fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> (PathBuf, Command) {
let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe");
// If our linker looks like a batch script on Windows then to execute this
// we'll need to spawn `cmd` explicitly. This is primarily done to handle
// emscripten where the linker is `emcc.bat` and needs to be spawned as
// `cmd /c emcc.bat ...`.
//
// This worked historically but is needed manually since #42436 (regression
// was tagged as #42791) and some more info can be found on #44443 for
// emscripten itself.
let mut cmd = match linker.to_str() {
Some(linker) if cfg!(windows) && linker.ends_with(".bat") => Command::bat_script(linker),
_ => match flavor {
LinkerFlavor::Lld(f) => Command::lld(linker, f),
LinkerFlavor::Msvc
if sess.opts.cg.linker.is_none() && sess.target.target.options.linker.is_none() =>
{
Command::new(msvc_tool.as_ref().map(|t| t.path()).unwrap_or(linker))
},
_ => Command::new(linker),
}
};
// The compiler's sysroot often has some bundled tools, so add it to the
// PATH for the child.
let mut new_path = sess.host_filesearch(PathKind::All)
.get_tools_search_paths();
let mut msvc_changed_path = false;
if sess.target.target.options.is_like_msvc {
if let Some(ref tool) = msvc_tool {
cmd.args(tool.args());
for &(ref k, ref v) in tool.env() {
if k == "PATH" {
new_path.extend(env::split_paths(v));
msvc_changed_path = true;
} else {
cmd.env(k, v);
}
}
}
}
if !msvc_changed_path {
if let Some(path) = env::var_os("PATH") {
new_path.extend(env::split_paths(&path));
}
}
cmd.env("PATH", env::join_paths(new_path).unwrap());
(linker.to_path_buf(), cmd)
}
pub fn remove(sess: &Session, path: &Path) {
if let Err(e) = fs::remove_file(path) {
sess.err(&format!("failed to remove {}: {}",
path.display(),
e));
}
}
/// Perform the linkage portion of the compilation phase. This will generate all
/// of the requested outputs for this compilation session.
@ -215,60 +152,6 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
false
}
pub(crate) fn each_linked_rlib(sess: &Session,
info: &CrateInfo,
f: &mut dyn FnMut(CrateNum, &Path)) -> Result<(), String> {
let crates = info.used_crates_static.iter();
let fmts = sess.dependency_formats.borrow();
let fmts = fmts.get(&config::CrateType::Executable)
.or_else(|| fmts.get(&config::CrateType::Staticlib))
.or_else(|| fmts.get(&config::CrateType::Cdylib))
.or_else(|| fmts.get(&config::CrateType::ProcMacro));
let fmts = match fmts {
Some(f) => f,
None => return Err("could not find formats for rlibs".to_string())
};
for &(cnum, ref path) in crates {
match fmts.get(cnum.as_usize() - 1) {
Some(&Linkage::NotLinked) |
Some(&Linkage::IncludedFromDylib) => continue,
Some(_) => {}
None => return Err("could not find formats for rlibs".to_string())
}
let name = &info.crate_name[&cnum];
let path = match *path {
LibSource::Some(ref p) => p,
LibSource::MetadataOnly => {
return Err(format!("could not find rlib for: `{}`, found rmeta (metadata) file",
name))
}
LibSource::None => {
return Err(format!("could not find rlib for: `{}`", name))
}
};
f(cnum, &path);
}
Ok(())
}
/// Returns a boolean indicating whether the specified crate should be ignored
/// during LTO.
///
/// Crates ignored during LTO are not lumped together in the "massive object
/// file" that we create and are linked in their normal rlib states. See
/// comments below for what crates do not participate in LTO.
///
/// It's unusual for a crate to not participate in LTO. Typically only
/// compiler-specific and unstable crates have a reason to not participate in
/// LTO.
pub(crate) fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool {
// If our target enables builtin function lowering in LLVM then the
// crates providing these functions don't participate in LTO (e.g.
// no_builtins or compiler builtins crates).
!sess.target.target.options.no_builtins &&
(info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum))
}
fn link_binary_output(sess: &Session,
codegen_results: &CodegenResults,
crate_type: config::CrateType,
@ -353,8 +236,11 @@ fn archive_config<'a>(sess: &'a Session,
/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
/// directory being searched for `extern crate` (observing an incomplete file).
/// The returned path is the temporary file containing the complete metadata.
fn emit_metadata<'a>(sess: &'a Session, codegen_results: &CodegenResults, tmpdir: &TempDir)
-> PathBuf {
fn emit_metadata<'a>(
sess: &'a Session,
codegen_results: &CodegenResults,
tmpdir: &TempDir
) -> PathBuf {
let out_filename = tmpdir.path().join(METADATA_FILENAME);
let result = fs::write(&out_filename, &codegen_results.metadata.raw_data);
@ -576,69 +462,6 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) {
}
}
pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
fn infer_from(
sess: &Session,
linker: Option<PathBuf>,
flavor: Option<LinkerFlavor>,
) -> Option<(PathBuf, LinkerFlavor)> {
match (linker, flavor) {
(Some(linker), Some(flavor)) => Some((linker, flavor)),
// only the linker flavor is known; use the default linker for the selected flavor
(None, Some(flavor)) => Some((PathBuf::from(match flavor {
LinkerFlavor::Em => if cfg!(windows) { "emcc.bat" } else { "emcc" },
LinkerFlavor::Gcc => "cc",
LinkerFlavor::Ld => "ld",
LinkerFlavor::Msvc => "link.exe",
LinkerFlavor::Lld(_) => "lld",
}), flavor)),
(Some(linker), None) => {
let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| {
sess.fatal("couldn't extract file stem from specified linker");
}).to_owned();
let flavor = if stem == "emcc" {
LinkerFlavor::Em
} else if stem == "gcc" || stem.ends_with("-gcc") {
LinkerFlavor::Gcc
} else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
LinkerFlavor::Ld
} else if stem == "link" || stem == "lld-link" {
LinkerFlavor::Msvc
} else if stem == "lld" || stem == "rust-lld" {
LinkerFlavor::Lld(sess.target.target.options.lld_flavor)
} else {
// fall back to the value in the target spec
sess.target.target.linker_flavor
};
Some((linker, flavor))
},
(None, None) => None,
}
}
// linker and linker flavor specified via command line have precedence over what the target
// specification specifies
if let Some(ret) = infer_from(
sess,
sess.opts.cg.linker.clone(),
sess.opts.debugging_opts.linker_flavor,
) {
return ret;
}
if let Some(ret) = infer_from(
sess,
sess.target.target.options.linker.clone().map(PathBuf::from),
Some(sess.target.target.linker_flavor),
) {
return ret;
}
bug!("Not enough information provided to determine how to invoke the linker");
}
// Create a dynamic library or executable
//
// This will invoke the system linker/cc to create the resulting file. This

View File

@ -9,12 +9,14 @@
// except according to those terms.
use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION};
use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
use back::write::{self, DiagnosticHandlers, pre_lto_bitcode_filename};
use rustc_codegen_ssa::back::symbol_export;
use rustc_codegen_ssa::back::write::{ModuleConfig, CodegenContext, pre_lto_bitcode_filename};
use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinShared, ThinModule};
use rustc_codegen_ssa::interfaces::*;
use back::write::{self, DiagnosticHandlers, with_llvm_pmb, save_temp_bitcode, get_llvm_opt_level};
use errors::{FatalError, Handler};
use llvm::archive_ro::ArchiveRO;
use llvm::{self, True, False};
use memmap;
use rustc::dep_graph::WorkProduct;
use rustc::dep_graph::cgu_reuse_tracker::CguReuse;
use rustc::hir::def_id::LOCAL_CRATE;
@ -22,9 +24,8 @@ use rustc::middle::exported_symbols::SymbolExportLevel;
use rustc::session::config::{self, Lto};
use rustc::util::common::time_ext;
use rustc_data_structures::fx::FxHashMap;
use rustc_codegen_utils::symbol_export;
use time_graph::Timeline;
use ModuleLlvm;
use {ModuleLlvm, LlvmCodegenBackend};
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
use libc;
@ -47,71 +48,16 @@ pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool {
}
}
pub(crate) enum LtoModuleCodegen {
Fat {
module: Option<ModuleCodegen<ModuleLlvm>>,
_serialized_bitcode: Vec<SerializedModule>,
},
Thin(ThinModule),
}
impl LtoModuleCodegen {
pub fn name(&self) -> &str {
match *self {
LtoModuleCodegen::Fat { .. } => "everything",
LtoModuleCodegen::Thin(ref m) => m.name(),
}
}
/// Optimize this module within the given codegen context.
///
/// This function is unsafe as it'll return a `ModuleCodegen` still
/// points to LLVM data structures owned by this `LtoModuleCodegen`.
/// It's intended that the module returned is immediately code generated and
/// dropped, and then this LTO module is dropped.
pub(crate) unsafe fn optimize(&mut self,
cgcx: &CodegenContext,
timeline: &mut Timeline)
-> Result<ModuleCodegen<ModuleLlvm>, FatalError>
{
match *self {
LtoModuleCodegen::Fat { ref mut module, .. } => {
let module = module.take().unwrap();
{
let config = cgcx.config(module.kind);
let llmod = module.module_llvm.llmod();
let tm = &*module.module_llvm.tm;
run_pass_manager(cgcx, tm, llmod, config, false);
timeline.record("fat-done");
}
Ok(module)
}
LtoModuleCodegen::Thin(ref mut thin) => thin.optimize(cgcx, timeline),
}
}
/// A "gauge" of how costly it is to optimize this module, used to sort
/// biggest modules first.
pub fn cost(&self) -> u64 {
match *self {
// Only one module with fat LTO, so the cost doesn't matter.
LtoModuleCodegen::Fat { .. } => 0,
LtoModuleCodegen::Thin(ref m) => m.cost(),
}
}
}
/// Performs LTO, which in the case of full LTO means merging all modules into
/// a single one and returning it for further optimizing. For ThinLTO, it will
/// do the global analysis necessary and return two lists, one of the modules
/// the need optimization and another for modules that can simply be copied over
/// from the incr. comp. cache.
pub(crate) fn run(cgcx: &CodegenContext,
pub(crate) fn run(cgcx: &CodegenContext<LlvmCodegenBackend>,
modules: Vec<ModuleCodegen<ModuleLlvm>>,
cached_modules: Vec<(SerializedModule, WorkProduct)>,
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
timeline: &mut Timeline)
-> Result<(Vec<LtoModuleCodegen>, Vec<WorkProduct>), FatalError>
-> Result<(Vec<LtoModuleCodegen<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError>
{
let diag_handler = cgcx.create_diag_handler();
let export_threshold = match cgcx.lto {
@ -230,13 +176,13 @@ pub(crate) fn run(cgcx: &CodegenContext,
}
}
fn fat_lto(cgcx: &CodegenContext,
fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
diag_handler: &Handler,
mut modules: Vec<ModuleCodegen<ModuleLlvm>>,
mut serialized_modules: Vec<(SerializedModule, CString)>,
mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
symbol_white_list: &[*const libc::c_char],
timeline: &mut Timeline)
-> Result<Vec<LtoModuleCodegen>, FatalError>
-> Result<Vec<LtoModuleCodegen<LlvmCodegenBackend>>, FatalError>
{
info!("going for a fat lto");
@ -303,7 +249,7 @@ fn fat_lto(cgcx: &CodegenContext,
serialized_bitcode.push(bc_decoded);
}
drop(linker);
cgcx.save_temp_bitcode(&module, "lto.input");
save_temp_bitcode(&cgcx, &module, "lto.input");
// Internalize everything that *isn't* in our whitelist to help strip out
// more modules and such
@ -312,14 +258,14 @@ fn fat_lto(cgcx: &CodegenContext,
llvm::LLVMRustRunRestrictionPass(llmod,
ptr as *const *const libc::c_char,
symbol_white_list.len() as libc::size_t);
cgcx.save_temp_bitcode(&module, "lto.after-restriction");
save_temp_bitcode(&cgcx, &module, "lto.after-restriction");
}
if cgcx.no_landing_pads {
unsafe {
llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
}
cgcx.save_temp_bitcode(&module, "lto.after-nounwind");
save_temp_bitcode(&cgcx, &module, "lto.after-nounwind");
}
timeline.record("passes");
}
@ -386,14 +332,14 @@ impl Drop for Linker<'a> {
/// calculating the *index* for ThinLTO. This index will then be shared amongst
/// all of the `LtoModuleCodegen` units returned below and destroyed once
/// they all go out of scope.
fn thin_lto(cgcx: &CodegenContext,
fn thin_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
diag_handler: &Handler,
modules: Vec<ModuleCodegen<ModuleLlvm>>,
serialized_modules: Vec<(SerializedModule, CString)>,
cached_modules: Vec<(SerializedModule, WorkProduct)>,
serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
symbol_white_list: &[*const libc::c_char],
timeline: &mut Timeline)
-> Result<(Vec<LtoModuleCodegen>, Vec<WorkProduct>), FatalError>
-> Result<(Vec<LtoModuleCodegen<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError>
{
unsafe {
info!("going for that thin, thin LTO");
@ -556,9 +502,8 @@ fn thin_lto(cgcx: &CodegenContext,
}
}
fn run_pass_manager(cgcx: &CodegenContext,
tm: &llvm::TargetMachine,
llmod: &llvm::Module,
pub(crate) fn run_pass_manager(cgcx: &CodegenContext<LlvmCodegenBackend>,
module: &ModuleCodegen<ModuleLlvm>,
config: &ModuleConfig,
thin: bool) {
// Now we have one massive module inside of llmod. Time to run the
@ -569,7 +514,7 @@ fn run_pass_manager(cgcx: &CodegenContext,
debug!("running the pass manager");
unsafe {
let pm = llvm::LLVMCreatePassManager();
llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
llvm::LLVMRustAddAnalysisPasses(module.module_llvm.tm, pm, module.module_llvm.llmod());
if config.verify_llvm_ir {
let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
@ -588,12 +533,13 @@ fn run_pass_manager(cgcx: &CodegenContext,
// Note that in general this shouldn't matter too much as you typically
// only turn on ThinLTO when you're compiling with optimizations
// otherwise.
let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
let opt_level = config.opt_level.map(get_llvm_opt_level)
.unwrap_or(llvm::CodeGenOptLevel::None);
let opt_level = match opt_level {
llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less,
level => level,
};
with_llvm_pmb(llmod, config, opt_level, false, &mut |b| {
with_llvm_pmb(module.module_llvm.llmod(), config, opt_level, false, &mut |b| {
if thin {
llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm);
} else {
@ -615,29 +561,14 @@ fn run_pass_manager(cgcx: &CodegenContext,
llvm::LLVMRustAddPass(pm, pass.unwrap());
}
time_ext(cgcx.time_passes, None, "LTO passes", || llvm::LLVMRunPassManager(pm, llmod));
time_ext(cgcx.time_passes, None, "LTO passes", ||
llvm::LLVMRunPassManager(pm, module.module_llvm.llmod()));
llvm::LLVMDisposePassManager(pm);
}
debug!("lto done");
}
pub enum SerializedModule {
Local(ModuleBuffer),
FromRlib(Vec<u8>),
FromUncompressedFile(memmap::Mmap),
}
impl SerializedModule {
fn data(&self) -> &[u8] {
match *self {
SerializedModule::Local(ref m) => m.data(),
SerializedModule::FromRlib(ref m) => m,
SerializedModule::FromUncompressedFile(ref m) => m,
}
}
}
pub struct ModuleBuffer(&'static mut llvm::ModuleBuffer);
unsafe impl Send for ModuleBuffer {}
@ -649,8 +580,10 @@ impl ModuleBuffer {
llvm::LLVMRustModuleBufferCreate(m)
})
}
}
pub fn data(&self) -> &[u8] {
impl ModuleBufferMethods for ModuleBuffer {
fn data(&self) -> &[u8] {
unsafe {
let ptr = llvm::LLVMRustModuleBufferPtr(self.0);
let len = llvm::LLVMRustModuleBufferLen(self.0);
@ -665,19 +598,7 @@ impl Drop for ModuleBuffer {
}
}
pub struct ThinModule {
shared: Arc<ThinShared>,
idx: usize,
}
struct ThinShared {
data: ThinData,
thin_buffers: Vec<ThinBuffer>,
serialized_modules: Vec<SerializedModule>,
module_names: Vec<CString>,
}
struct ThinData(&'static mut llvm::ThinLTOData);
pub struct ThinData(&'static mut llvm::ThinLTOData);
unsafe impl Send for ThinData {}
unsafe impl Sync for ThinData {}
@ -702,8 +623,10 @@ impl ThinBuffer {
ThinBuffer(buffer)
}
}
}
pub fn data(&self) -> &[u8] {
impl ThinBufferMethods for ThinBuffer {
fn data(&self) -> &[u8] {
unsafe {
let ptr = llvm::LLVMRustThinLTOBufferPtr(self.0) as *const _;
let len = llvm::LLVMRustThinLTOBufferLen(self.0);
@ -720,161 +643,142 @@ impl Drop for ThinBuffer {
}
}
impl ThinModule {
fn name(&self) -> &str {
self.shared.module_names[self.idx].to_str().unwrap()
}
pub unsafe fn optimize_thin_module(
thin_module: &mut ThinModule<LlvmCodegenBackend>,
cgcx: &CodegenContext<LlvmCodegenBackend>,
timeline: &mut Timeline
) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
let diag_handler = cgcx.create_diag_handler();
let tm = (cgcx.tm_factory)().map_err(|e| {
write::llvm_err(&diag_handler, &e)
})?;
fn cost(&self) -> u64 {
// Yes, that's correct, we're using the size of the bytecode as an
// indicator for how costly this codegen unit is.
self.data().len() as u64
}
fn data(&self) -> &[u8] {
let a = self.shared.thin_buffers.get(self.idx).map(|b| b.data());
a.unwrap_or_else(|| {
let len = self.shared.thin_buffers.len();
self.shared.serialized_modules[self.idx - len].data()
})
}
unsafe fn optimize(&mut self, cgcx: &CodegenContext, timeline: &mut Timeline)
-> Result<ModuleCodegen<ModuleLlvm>, FatalError>
{
let diag_handler = cgcx.create_diag_handler();
let tm = (cgcx.tm_factory)().map_err(|e| {
write::llvm_err(&diag_handler, &e)
})?;
// Right now the implementation we've got only works over serialized
// modules, so we create a fresh new LLVM context and parse the module
// into that context. One day, however, we may do this for upstream
// crates but for locally codegened modules we may be able to reuse
// that LLVM Context and Module.
let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
let llmod_raw = llvm::LLVMRustParseBitcodeForThinLTO(
// Right now the implementation we've got only works over serialized
// modules, so we create a fresh new LLVM context and parse the module
// into that context. One day, however, we may do this for upstream
// crates but for locally codegened modules we may be able to reuse
// that LLVM Context and Module.
let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
let llmod_raw = llvm::LLVMRustParseBitcodeForThinLTO(
llcx,
thin_module.data().as_ptr(),
thin_module.data().len(),
thin_module.shared.module_names[thin_module.idx].as_ptr(),
).ok_or_else(|| {
let msg = "failed to parse bitcode for thin LTO module";
write::llvm_err(&diag_handler, msg)
})? as *const _;
let module = ModuleCodegen {
module_llvm: ModuleLlvm {
llmod_raw,
llcx,
self.data().as_ptr(),
self.data().len(),
self.shared.module_names[self.idx].as_ptr(),
).ok_or_else(|| {
let msg = "failed to parse bitcode for thin LTO module";
write::llvm_err(&diag_handler, msg)
})? as *const _;
let module = ModuleCodegen {
module_llvm: ModuleLlvm {
llmod_raw,
llcx,
tm,
},
name: self.name().to_string(),
kind: ModuleKind::Regular,
};
{
let llmod = module.module_llvm.llmod();
cgcx.save_temp_bitcode(&module, "thin-lto-input");
tm,
},
name: thin_module.name().to_string(),
kind: ModuleKind::Regular,
};
{
let llmod = module.module_llvm.llmod();
save_temp_bitcode(&cgcx, &module, "thin-lto-input");
// Before we do much else find the "main" `DICompileUnit` that we'll be
// using below. If we find more than one though then rustc has changed
// in a way we're not ready for, so generate an ICE by returning
// an error.
let mut cu1 = ptr::null_mut();
let mut cu2 = ptr::null_mut();
llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2);
if !cu2.is_null() {
let msg = "multiple source DICompileUnits found";
return Err(write::llvm_err(&diag_handler, msg))
}
// Like with "fat" LTO, get some better optimizations if landing pads
// are disabled by removing all landing pads.
if cgcx.no_landing_pads {
llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
cgcx.save_temp_bitcode(&module, "thin-lto-after-nounwind");
timeline.record("nounwind");
}
// Up next comes the per-module local analyses that we do for Thin LTO.
// Each of these functions is basically copied from the LLVM
// implementation and then tailored to suit this implementation. Ideally
// each of these would be supported by upstream LLVM but that's perhaps
// a patch for another day!
//
// You can find some more comments about these functions in the LLVM
// bindings we've got (currently `PassWrapper.cpp`)
if !llvm::LLVMRustPrepareThinLTORename(self.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
cgcx.save_temp_bitcode(&module, "thin-lto-after-rename");
timeline.record("rename");
if !llvm::LLVMRustPrepareThinLTOResolveWeak(self.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
cgcx.save_temp_bitcode(&module, "thin-lto-after-resolve");
timeline.record("resolve");
if !llvm::LLVMRustPrepareThinLTOInternalize(self.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
cgcx.save_temp_bitcode(&module, "thin-lto-after-internalize");
timeline.record("internalize");
if !llvm::LLVMRustPrepareThinLTOImport(self.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
cgcx.save_temp_bitcode(&module, "thin-lto-after-import");
timeline.record("import");
// Ok now this is a bit unfortunate. This is also something you won't
// find upstream in LLVM's ThinLTO passes! This is a hack for now to
// work around bugs in LLVM.
//
// First discovered in #45511 it was found that as part of ThinLTO
// importing passes LLVM will import `DICompileUnit` metadata
// information across modules. This means that we'll be working with one
// LLVM module that has multiple `DICompileUnit` instances in it (a
// bunch of `llvm.dbg.cu` members). Unfortunately there's a number of
// bugs in LLVM's backend which generates invalid DWARF in a situation
// like this:
//
// https://bugs.llvm.org/show_bug.cgi?id=35212
// https://bugs.llvm.org/show_bug.cgi?id=35562
//
// While the first bug there is fixed the second ended up causing #46346
// which was basically a resurgence of #45511 after LLVM's bug 35212 was
// fixed.
//
// This function below is a huge hack around this problem. The function
// below is defined in `PassWrapper.cpp` and will basically "merge"
// all `DICompileUnit` instances in a module. Basically it'll take all
// the objects, rewrite all pointers of `DISubprogram` to point to the
// first `DICompileUnit`, and then delete all the other units.
//
// This is probably mangling to the debug info slightly (but hopefully
// not too much) but for now at least gets LLVM to emit valid DWARF (or
// so it appears). Hopefully we can remove this once upstream bugs are
// fixed in LLVM.
llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1);
cgcx.save_temp_bitcode(&module, "thin-lto-after-patch");
timeline.record("patch");
// Alright now that we've done everything related to the ThinLTO
// analysis it's time to run some optimizations! Here we use the same
// `run_pass_manager` as the "fat" LTO above except that we tell it to
// populate a thin-specific pass manager, which presumably LLVM treats a
// little differently.
info!("running thin lto passes over {}", module.name);
let config = cgcx.config(module.kind);
run_pass_manager(cgcx, module.module_llvm.tm, llmod, config, true);
cgcx.save_temp_bitcode(&module, "thin-lto-after-pm");
timeline.record("thin-done");
// Before we do much else find the "main" `DICompileUnit` that we'll be
// using below. If we find more than one though then rustc has changed
// in a way we're not ready for, so generate an ICE by returning
// an error.
let mut cu1 = ptr::null_mut();
let mut cu2 = ptr::null_mut();
llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2);
if !cu2.is_null() {
let msg = "multiple source DICompileUnits found";
return Err(write::llvm_err(&diag_handler, msg))
}
Ok(module)
// Like with "fat" LTO, get some better optimizations if landing pads
// are disabled by removing all landing pads.
if cgcx.no_landing_pads {
llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
save_temp_bitcode(&cgcx, &module, "thin-lto-after-nounwind");
timeline.record("nounwind");
}
// Up next comes the per-module local analyses that we do for Thin LTO.
// Each of these functions is basically copied from the LLVM
// implementation and then tailored to suit this implementation. Ideally
// each of these would be supported by upstream LLVM but that's perhaps
// a patch for another day!
//
// You can find some more comments about these functions in the LLVM
// bindings we've got (currently `PassWrapper.cpp`)
if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-rename");
timeline.record("rename");
if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve");
timeline.record("resolve");
if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize");
timeline.record("internalize");
if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod) {
let msg = "failed to prepare thin LTO module";
return Err(write::llvm_err(&diag_handler, msg))
}
save_temp_bitcode(cgcx, &module, "thin-lto-after-import");
timeline.record("import");
// Ok now this is a bit unfortunate. This is also something you won't
// find upstream in LLVM's ThinLTO passes! This is a hack for now to
// work around bugs in LLVM.
//
// First discovered in #45511 it was found that as part of ThinLTO
// importing passes LLVM will import `DICompileUnit` metadata
// information across modules. This means that we'll be working with one
// LLVM module that has multiple `DICompileUnit` instances in it (a
// bunch of `llvm.dbg.cu` members). Unfortunately there's a number of
// bugs in LLVM's backend which generates invalid DWARF in a situation
// like this:
//
// https://bugs.llvm.org/show_bug.cgi?id=35212
// https://bugs.llvm.org/show_bug.cgi?id=35562
//
// While the first bug there is fixed the second ended up causing #46346
// which was basically a resurgence of #45511 after LLVM's bug 35212 was
// fixed.
//
// This function below is a huge hack around this problem. The function
// below is defined in `PassWrapper.cpp` and will basically "merge"
// all `DICompileUnit` instances in a module. Basically it'll take all
// the objects, rewrite all pointers of `DISubprogram` to point to the
// first `DICompileUnit`, and then delete all the other units.
//
// This is probably mangling to the debug info slightly (but hopefully
// not too much) but for now at least gets LLVM to emit valid DWARF (or
// so it appears). Hopefully we can remove this once upstream bugs are
// fixed in LLVM.
llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1);
save_temp_bitcode(cgcx, &module, "thin-lto-after-patch");
timeline.record("patch");
// Alright now that we've done everything related to the ThinLTO
// analysis it's time to run some optimizations! Here we use the same
// `run_pass_manager` as the "fat" LTO above except that we tell it to
// populate a thin-specific pass manager, which presumably LLVM treats a
// little differently.
info!("running thin lto passes over {}", module.name);
let config = cgcx.config(module.kind);
run_pass_manager(cgcx, &module, config, true);
save_temp_bitcode(cgcx, &module, "thin-lto-after-pm");
timeline.record("thin-done");
}
Ok(module)
}
#[derive(Debug, Default)]

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,6 @@ use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
use super::LlvmCodegenBackend;
use back::write;
use llvm;
use metadata;
use rustc::mir::mono::{Linkage, Visibility, Stats};
@ -44,6 +43,7 @@ use rustc_codegen_ssa::mono_item::MonoItemExt;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_codegen_ssa::interfaces::*;
use rustc_codegen_ssa::back::write::submit_codegened_module_to_llvm;
use std::ffi::CString;
use std::time::Instant;
@ -53,7 +53,7 @@ use rustc::hir::CodegenFnAttrs;
use value::Value;
pub(crate) fn write_metadata<'a, 'gcx>(
pub fn write_metadata<'a, 'gcx>(
tcx: TyCtxt<'a, 'gcx, 'gcx>,
llvm_module: &ModuleLlvm
) -> EncodedMetadata {
@ -163,9 +163,7 @@ pub fn compile_codegen_unit<'ll, 'tcx>(tcx: TyCtxt<'ll, 'tcx, 'tcx>,
let cost = time_to_codegen.as_secs() * 1_000_000_000 +
time_to_codegen.subsec_nanos() as u64;
write::submit_codegened_module_to_llvm(tcx,
module,
cost);
submit_codegened_module_to_llvm(&LlvmCodegenBackend(()), tcx, module, cost);
return stats;
fn module_codegen<'ll, 'tcx>(

View File

@ -68,15 +68,17 @@ extern crate tempfile;
extern crate memmap;
use rustc_codegen_ssa::interfaces::*;
use time_graph::TimeGraph;
use std::sync::mpsc::Receiver;
use back::write::{self, OngoingCodegen};
use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig};
use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinModule};
use rustc_codegen_ssa::CompiledModule;
use errors::{FatalError, Handler};
use rustc::dep_graph::WorkProduct;
use rustc::util::time_graph::Timeline;
use syntax_pos::symbol::InternedString;
use rustc::mir::mono::Stats;
pub use llvm_util::target_features;
use std::any::Any;
use std::sync::mpsc;
use std::sync::{mpsc, Arc};
use rustc::dep_graph::DepGraph;
use rustc::middle::allocator::AllocatorKind;
@ -87,9 +89,8 @@ use rustc::ty::{self, TyCtxt};
use rustc::util::time_graph;
use rustc::util::profiling::ProfileCategory;
use rustc_mir::monomorphize;
use rustc_codegen_ssa::{ModuleCodegen, CompiledModule, CachedModuleCodegen, CrateInfo};
use rustc_codegen_ssa::ModuleCodegen;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use rustc_data_structures::svh::Svh;
mod diagnostics;
@ -127,12 +128,10 @@ mod type_;
mod type_of;
mod value;
#[derive(Clone)]
pub struct LlvmCodegenBackend(());
impl ExtraBackendMethods for LlvmCodegenBackend {
type Module = ModuleLlvm;
type OngoingCodegen = OngoingCodegen;
fn new_metadata(&self, sess: &Session, mod_name: &str) -> ModuleLlvm {
ModuleLlvm::new(sess, mod_name)
}
@ -143,45 +142,9 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
) -> EncodedMetadata {
base::write_metadata(tcx, metadata)
}
fn start_async_codegen(
&self,
tcx: TyCtxt,
time_graph: Option<TimeGraph>,
metadata: EncodedMetadata,
coordinator_receive: Receiver<Box<dyn Any + Send>>,
total_cgus: usize
) -> OngoingCodegen {
write::start_async_codegen(tcx, time_graph, metadata, coordinator_receive, total_cgus)
}
fn submit_pre_codegened_module_to_backend(
&self,
codegen: &OngoingCodegen,
tcx: TyCtxt,
module: ModuleCodegen<ModuleLlvm>
) {
codegen.submit_pre_codegened_module_to_llvm(tcx, module)
}
fn submit_pre_lto_module_to_backend(&self, tcx: TyCtxt, module: CachedModuleCodegen) {
write::submit_pre_lto_module_to_llvm(tcx, module)
}
fn submit_post_lto_module_to_backend(&self, tcx: TyCtxt, module: CachedModuleCodegen) {
write::submit_post_lto_module_to_llvm(tcx, module)
}
fn codegen_aborted(codegen: OngoingCodegen) {
codegen.codegen_aborted();
}
fn codegen_finished(&self, codegen: &OngoingCodegen, tcx: TyCtxt) {
codegen.codegen_finished(tcx)
}
fn check_for_errors(&self, codegen: &OngoingCodegen, sess: &Session) {
codegen.check_for_errors(sess)
}
fn codegen_allocator(&self, tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) {
unsafe { allocator::codegen(tcx, mods, kind) }
}
fn wait_for_signal_to_codegen_item(&self, codegen: &OngoingCodegen) {
codegen.wait_for_signal_to_codegen_item()
}
fn compile_codegen_unit<'a, 'tcx: 'a>(
&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
@ -189,11 +152,85 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
) -> Stats {
base::compile_codegen_unit(tcx, cgu_name)
}
fn target_machine_factory(
&self,
sess: &Session,
find_features: bool
) -> Arc<dyn Fn() ->
Result<&'static mut llvm::TargetMachine, String> + Send + Sync> {
back::write::target_machine_factory(sess, find_features)
}
fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str {
llvm_util::target_cpu(sess)
}
}
impl Clone for &'static mut llvm::TargetMachine {
fn clone(&self) -> Self {
// This method should never be called. It is put here because in
// rustc_codegen_ssa::back::write::CodegenContext, the TargetMachine is contained in a
// closure returned by a function under an Arc. The clone-deriving algorithm works when the
// struct contains the original LLVM TargetMachine type but not any more when supplied with
// a generic type. Hence this dummy Clone implementation.
panic!()
}
}
impl !Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis
impl !Sync for LlvmCodegenBackend {}
impl WriteBackendMethods for LlvmCodegenBackend {
type Module = ModuleLlvm;
type ModuleBuffer = back::lto::ModuleBuffer;
type Context = llvm::Context;
type TargetMachine = &'static mut llvm::TargetMachine;
type ThinData = back::lto::ThinData;
type ThinBuffer = back::lto::ThinBuffer;
fn print_pass_timings(&self) {
unsafe { llvm::LLVMRustPrintPassTimings(); }
}
fn run_lto(
cgcx: &CodegenContext<Self>,
modules: Vec<ModuleCodegen<Self::Module>>,
cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
timeline: &mut Timeline
) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
back::lto::run(cgcx, modules, cached_modules, timeline)
}
unsafe fn optimize(
cgcx: &CodegenContext<Self>,
diag_handler: &Handler,
module: &ModuleCodegen<Self::Module>,
config: &ModuleConfig,
timeline: &mut Timeline
) -> Result<(), FatalError> {
back::write::optimize(cgcx, diag_handler, module, config, timeline)
}
unsafe fn optimize_thin(
cgcx: &CodegenContext<Self>,
thin: &mut ThinModule<Self>,
timeline: &mut Timeline
) -> Result<ModuleCodegen<Self::Module>, FatalError> {
back::lto::optimize_thin_module(thin, cgcx, timeline)
}
unsafe fn codegen(
cgcx: &CodegenContext<Self>,
diag_handler: &Handler,
module: ModuleCodegen<Self::Module>,
config: &ModuleConfig,
timeline: &mut Timeline
) -> Result<CompiledModule, FatalError> {
back::write::codegen(cgcx, diag_handler, module, config, timeline)
}
fn run_lto_pass_manager(
cgcx: &CodegenContext<Self>,
module: &ModuleCodegen<Self::Module>,
config: &ModuleConfig,
thin: bool
) {
back::lto::run_pass_manager(cgcx, module, config, thin)
}
}
unsafe impl<'a> Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis
unsafe impl<'a> Sync for LlvmCodegenBackend {}
impl LlvmCodegenBackend {
pub fn new() -> Box<dyn CodegenBackend> {
@ -201,7 +238,7 @@ impl LlvmCodegenBackend {
}
}
impl CodegenBackend for LlvmCodegenBackend {
impl<'a> CodegenBackend for LlvmCodegenBackend {
fn init(&self, sess: &Session) {
llvm_util::init(sess); // Make sure llvm is inited
}
@ -254,21 +291,21 @@ impl CodegenBackend for LlvmCodegenBackend {
}
fn provide(&self, providers: &mut ty::query::Providers) {
rustc_codegen_utils::symbol_export::provide(providers);
rustc_codegen_utils::symbol_names::provide(providers);
rustc_codegen_ssa::back::symbol_export::provide(providers);
rustc_codegen_ssa::base::provide_both(providers);
attributes::provide(providers);
}
fn provide_extern(&self, providers: &mut ty::query::Providers) {
rustc_codegen_utils::symbol_export::provide_extern(providers);
rustc_codegen_ssa::back::symbol_export::provide_extern(providers);
rustc_codegen_ssa::base::provide_both(providers);
attributes::provide_extern(providers);
}
fn codegen_crate<'a, 'tcx>(
fn codegen_crate<'b, 'tcx>(
&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
tcx: TyCtxt<'b, 'tcx, 'tcx>,
rx: mpsc::Receiver<Box<dyn Any + Send>>
) -> Box<dyn Any> {
box rustc_codegen_ssa::base::codegen_crate(LlvmCodegenBackend(()), tcx, rx)
@ -282,12 +319,13 @@ impl CodegenBackend for LlvmCodegenBackend {
outputs: &OutputFilenames,
) -> Result<(), CompileIncomplete>{
use rustc::util::common::time;
let (ongoing_codegen, work_products) =
ongoing_codegen.downcast::<::back::write::OngoingCodegen>()
let (codegen_results, work_products) =
ongoing_codegen.downcast::
<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
.expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
.join(sess);
if sess.opts.debugging_opts.incremental_info {
back::write::dump_incremental_data(&ongoing_codegen);
rustc_codegen_ssa::back::write::dump_incremental_data(&codegen_results);
}
time(sess,
@ -305,14 +343,14 @@ impl CodegenBackend for LlvmCodegenBackend {
// This should produce either a finished executable or library.
sess.profiler(|p| p.start_activity(ProfileCategory::Linking));
time(sess, "linking", || {
back::link::link_binary(sess, &ongoing_codegen,
outputs, &ongoing_codegen.crate_name.as_str());
back::link::link_binary(sess, &codegen_results,
outputs, &codegen_results.crate_name.as_str());
});
sess.profiler(|p| p.end_activity(ProfileCategory::Linking));
// Now that we won't touch anything in the incremental compilation directory
// any more, we can finalize it (which involves renaming it)
rustc_incremental::finalize_session_directory(sess, ongoing_codegen.crate_hash);
rustc_incremental::finalize_session_directory(sess, codegen_results.crate_hash);
Ok(())
}
@ -363,15 +401,4 @@ impl Drop for ModuleLlvm {
}
}
struct CodegenResults {
crate_name: Symbol,
modules: Vec<CompiledModule>,
allocator_module: Option<CompiledModule>,
metadata_module: CompiledModule,
crate_hash: Svh,
metadata: rustc::middle::cstore::EncodedMetadata,
windows_subsystem: Option<String>,
linker_info: rustc_codegen_utils::linker::LinkerInfo,
crate_info: CrateInfo,
}
__build_diagnostic_array! { librustc_codegen_llvm, DIAGNOSTICS }

View File

@ -9,3 +9,7 @@ path = "lib.rs"
test = false
[dependencies]
cc = "1.0.1"
num_cpus = "1.0"
rustc-demangle = "0.1.4"
memmap = "0.6"

View File

@ -0,0 +1,36 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::session::Session;
use std::path::PathBuf;
pub fn find_library(name: &str, search_paths: &[PathBuf], sess: &Session)
-> PathBuf {
// On Windows, static libraries sometimes show up as libfoo.a and other
// times show up as foo.lib
let oslibname = format!("{}{}{}",
sess.target.target.options.staticlib_prefix,
name,
sess.target.target.options.staticlib_suffix);
let unixlibname = format!("lib{}.a", name);
for path in search_paths {
debug!("looking for {} inside {:?}", name, path);
let test = path.join(&oslibname);
if test.exists() { return test }
if oslibname != unixlibname {
let test = path.join(&unixlibname);
if test.exists() { return test }
}
}
sess.fatal(&format!("could not find native static library `{}`, \
perhaps an -L flag is missing?", name));
}

View File

@ -0,0 +1,208 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/// For all the linkers we support, and information they might
/// need out of the shared crate context before we get rid of it.
use rustc::session::{Session, config};
use rustc::session::search_paths::PathKind;
use rustc::middle::dependency_format::Linkage;
use rustc::middle::cstore::LibSource;
use rustc_target::spec::LinkerFlavor;
use rustc::hir::def_id::CrateNum;
use super::command::Command;
use CrateInfo;
use cc::windows_registry;
use std::fs;
use std::path::{Path, PathBuf};
use std::env;
pub fn remove(sess: &Session, path: &Path) {
if let Err(e) = fs::remove_file(path) {
sess.err(&format!("failed to remove {}: {}",
path.display(),
e));
}
}
// The third parameter is for env vars, used on windows to set up the
// path for MSVC to find its DLLs, and gcc to find its bundled
// toolchain
pub fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> (PathBuf, Command) {
let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe");
// If our linker looks like a batch script on Windows then to execute this
// we'll need to spawn `cmd` explicitly. This is primarily done to handle
// emscripten where the linker is `emcc.bat` and needs to be spawned as
// `cmd /c emcc.bat ...`.
//
// This worked historically but is needed manually since #42436 (regression
// was tagged as #42791) and some more info can be found on #44443 for
// emscripten itself.
let mut cmd = match linker.to_str() {
Some(linker) if cfg!(windows) && linker.ends_with(".bat") => Command::bat_script(linker),
_ => match flavor {
LinkerFlavor::Lld(f) => Command::lld(linker, f),
LinkerFlavor::Msvc
if sess.opts.cg.linker.is_none() && sess.target.target.options.linker.is_none() =>
{
Command::new(msvc_tool.as_ref().map(|t| t.path()).unwrap_or(linker))
},
_ => Command::new(linker),
}
};
// The compiler's sysroot often has some bundled tools, so add it to the
// PATH for the child.
let mut new_path = sess.host_filesearch(PathKind::All)
.get_tools_search_paths();
let mut msvc_changed_path = false;
if sess.target.target.options.is_like_msvc {
if let Some(ref tool) = msvc_tool {
cmd.args(tool.args());
for &(ref k, ref v) in tool.env() {
if k == "PATH" {
new_path.extend(env::split_paths(v));
msvc_changed_path = true;
} else {
cmd.env(k, v);
}
}
}
}
if !msvc_changed_path {
if let Some(path) = env::var_os("PATH") {
new_path.extend(env::split_paths(&path));
}
}
cmd.env("PATH", env::join_paths(new_path).unwrap());
(linker.to_path_buf(), cmd)
}
pub fn each_linked_rlib(sess: &Session,
info: &CrateInfo,
f: &mut dyn FnMut(CrateNum, &Path)) -> Result<(), String> {
let crates = info.used_crates_static.iter();
let fmts = sess.dependency_formats.borrow();
let fmts = fmts.get(&config::CrateType::Executable)
.or_else(|| fmts.get(&config::CrateType::Staticlib))
.or_else(|| fmts.get(&config::CrateType::Cdylib))
.or_else(|| fmts.get(&config::CrateType::ProcMacro));
let fmts = match fmts {
Some(f) => f,
None => return Err("could not find formats for rlibs".to_string())
};
for &(cnum, ref path) in crates {
match fmts.get(cnum.as_usize() - 1) {
Some(&Linkage::NotLinked) |
Some(&Linkage::IncludedFromDylib) => continue,
Some(_) => {}
None => return Err("could not find formats for rlibs".to_string())
}
let name = &info.crate_name[&cnum];
let path = match *path {
LibSource::Some(ref p) => p,
LibSource::MetadataOnly => {
return Err(format!("could not find rlib for: `{}`, found rmeta (metadata) file",
name))
}
LibSource::None => {
return Err(format!("could not find rlib for: `{}`", name))
}
};
f(cnum, &path);
}
Ok(())
}
/// Returns a boolean indicating whether the specified crate should be ignored
/// during LTO.
///
/// Crates ignored during LTO are not lumped together in the "massive object
/// file" that we create and are linked in their normal rlib states. See
/// comments below for what crates do not participate in LTO.
///
/// It's unusual for a crate to not participate in LTO. Typically only
/// compiler-specific and unstable crates have a reason to not participate in
/// LTO.
pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool {
// If our target enables builtin function lowering in LLVM then the
// crates providing these functions don't participate in LTO (e.g.
// no_builtins or compiler builtins crates).
!sess.target.target.options.no_builtins &&
(info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum))
}
pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
fn infer_from(
sess: &Session,
linker: Option<PathBuf>,
flavor: Option<LinkerFlavor>,
) -> Option<(PathBuf, LinkerFlavor)> {
match (linker, flavor) {
(Some(linker), Some(flavor)) => Some((linker, flavor)),
// only the linker flavor is known; use the default linker for the selected flavor
(None, Some(flavor)) => Some((PathBuf::from(match flavor {
LinkerFlavor::Em => if cfg!(windows) { "emcc.bat" } else { "emcc" },
LinkerFlavor::Gcc => "cc",
LinkerFlavor::Ld => "ld",
LinkerFlavor::Msvc => "link.exe",
LinkerFlavor::Lld(_) => "lld",
}), flavor)),
(Some(linker), None) => {
let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| {
sess.fatal("couldn't extract file stem from specified linker");
}).to_owned();
let flavor = if stem == "emcc" {
LinkerFlavor::Em
} else if stem == "gcc" || stem.ends_with("-gcc") {
LinkerFlavor::Gcc
} else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
LinkerFlavor::Ld
} else if stem == "link" || stem == "lld-link" {
LinkerFlavor::Msvc
} else if stem == "lld" || stem == "rust-lld" {
LinkerFlavor::Lld(sess.target.target.options.lld_flavor)
} else {
// fall back to the value in the target spec
sess.target.target.linker_flavor
};
Some((linker, flavor))
},
(None, None) => None,
}
}
// linker and linker flavor specified via command line have precedence over what the target
// specification specifies
if let Some(ret) = infer_from(
sess,
sess.opts.cg.linker.clone(),
sess.opts.debugging_opts.linker_flavor,
) {
return ret;
}
if let Some(ret) = infer_from(
sess,
sess.target.target.options.linker.clone().map(PathBuf::from),
Some(sess.target.target.linker_flavor),
) {
return ret;
}
bug!("Not enough information provided to determine how to invoke the linker");
}

View File

@ -8,6 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::symbol_export;
use super::command::Command;
use super::archive;
use rustc_data_structures::fx::FxHashMap;
use std::ffi::{OsStr, OsString};
use std::fs::{self, File};
@ -15,7 +19,6 @@ use std::io::prelude::*;
use std::io::{self, BufWriter};
use std::path::{Path, PathBuf};
use command::Command;
use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
use rustc::middle::dependency_format::Linkage;
use rustc::session::Session;
@ -256,7 +259,7 @@ impl<'a> Linker for GccLinker<'a> {
// -force_load is the macOS equivalent of --whole-archive, but it
// involves passing the full path to the library to link.
self.linker_arg("-force_load");
let lib = ::find_library(lib, search_path, &self.sess);
let lib = archive::find_library(lib, search_path, &self.sess);
self.linker_arg(&lib);
}
}
@ -878,36 +881,6 @@ impl<'a> Linker for EmLinker<'a> {
}
}
fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec<String> {
let mut symbols = Vec::new();
let export_threshold =
::symbol_export::crates_export_threshold(&[crate_type]);
for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() {
if level.is_below_threshold(export_threshold) {
symbols.push(symbol.symbol_name(tcx).to_string());
}
}
let formats = tcx.sess.dependency_formats.borrow();
let deps = formats[&crate_type].iter();
for (index, dep_format) in deps.enumerate() {
let cnum = CrateNum::new(index + 1);
// For each dependency that we are linking to statically ...
if *dep_format == Linkage::Static {
// ... we add its symbol list to our export list.
for &(symbol, level) in tcx.exported_symbols(cnum).iter() {
if level.is_below_threshold(export_threshold) {
symbols.push(symbol.symbol_name(tcx).to_string());
}
}
}
}
symbols
}
pub struct WasmLd<'a> {
cmd: Command,
sess: &'a Session,
@ -1075,3 +1048,32 @@ impl<'a> Linker for WasmLd<'a> {
// Do nothing for now
}
}
fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec<String> {
let mut symbols = Vec::new();
let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() {
if level.is_below_threshold(export_threshold) {
symbols.push(symbol.symbol_name(tcx).to_string());
}
}
let formats = tcx.sess.dependency_formats.borrow();
let deps = formats[&crate_type].iter();
for (index, dep_format) in deps.enumerate() {
let cnum = CrateNum::new(index + 1);
// For each dependency that we are linking to statically ...
if *dep_format == Linkage::Static {
// ... we add its symbol list to our export list.
for &(symbol, level) in tcx.exported_symbols(cnum).iter() {
if level.is_below_threshold(export_threshold) {
symbols.push(symbol.symbol_name(tcx).to_string());
}
}
}
}
symbols
}

View File

@ -0,0 +1,122 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::write::CodegenContext;
use interfaces::*;
use ModuleCodegen;
use rustc::util::time_graph::Timeline;
use rustc_errors::FatalError;
use std::sync::Arc;
use std::ffi::CString;
pub struct ThinModule<B: WriteBackendMethods> {
pub shared: Arc<ThinShared<B>>,
pub idx: usize,
}
impl<B: WriteBackendMethods> ThinModule<B> {
pub fn name(&self) -> &str {
self.shared.module_names[self.idx].to_str().unwrap()
}
pub fn cost(&self) -> u64 {
// Yes, that's correct, we're using the size of the bytecode as an
// indicator for how costly this codegen unit is.
self.data().len() as u64
}
pub fn data(&self) -> &[u8] {
let a = self.shared.thin_buffers.get(self.idx).map(|b| b.data());
a.unwrap_or_else(|| {
let len = self.shared.thin_buffers.len();
self.shared.serialized_modules[self.idx - len].data()
})
}
}
pub struct ThinShared<B: WriteBackendMethods> {
pub data: B::ThinData,
pub thin_buffers: Vec<B::ThinBuffer>,
pub serialized_modules: Vec<SerializedModule<B::ModuleBuffer>>,
pub module_names: Vec<CString>,
}
pub enum LtoModuleCodegen<B: WriteBackendMethods> {
Fat {
module: Option<ModuleCodegen<B::Module>>,
_serialized_bitcode: Vec<SerializedModule<B::ModuleBuffer>>,
},
Thin(ThinModule<B>),
}
impl<B: WriteBackendMethods> LtoModuleCodegen<B> {
pub fn name(&self) -> &str {
match *self {
LtoModuleCodegen::Fat { .. } => "everything",
LtoModuleCodegen::Thin(ref m) => m.name(),
}
}
/// Optimize this module within the given codegen context.
///
/// This function is unsafe as it'll return a `ModuleCodegen` still
/// points to LLVM data structures owned by this `LtoModuleCodegen`.
/// It's intended that the module returned is immediately code generated and
/// dropped, and then this LTO module is dropped.
pub unsafe fn optimize(
&mut self,
cgcx: &CodegenContext<B>,
timeline: &mut Timeline
) -> Result<ModuleCodegen<B::Module>, FatalError> {
match *self {
LtoModuleCodegen::Fat { ref mut module, .. } => {
let module = module.take().unwrap();
{
let config = cgcx.config(module.kind);
B::run_lto_pass_manager(cgcx, &module, config, false);
timeline.record("fat-done");
}
Ok(module)
}
LtoModuleCodegen::Thin(ref mut thin) => B::optimize_thin(cgcx, thin, timeline),
}
}
/// A "gauge" of how costly it is to optimize this module, used to sort
/// biggest modules first.
pub fn cost(&self) -> u64 {
match *self {
// Only one module with fat LTO, so the cost doesn't matter.
LtoModuleCodegen::Fat { .. } => 0,
LtoModuleCodegen::Thin(ref m) => m.cost(),
}
}
}
pub enum SerializedModule<M: ModuleBufferMethods> {
Local(M),
FromRlib(Vec<u8>),
FromUncompressedFile(memmap::Mmap),
}
impl<M: ModuleBufferMethods> SerializedModule<M> {
pub fn data(&self) -> &[u8] {
match *self {
SerializedModule::Local(ref m) => m.data(),
SerializedModule::FromRlib(ref m) => m,
SerializedModule::FromUncompressedFile(ref m) => m,
}
}
}

View File

@ -0,0 +1,17 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub mod write;
pub mod linker;
pub mod lto;
pub mod link;
pub mod command;
pub mod symbol_export;
pub mod archive;

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,8 @@ use rustc::util::profiling::ProfileCategory;
use rustc::session::config::{self, EntryFnType, Lto};
use rustc::session::Session;
use mir::place::PlaceRef;
use back::write::{OngoingCodegen, start_async_codegen, submit_pre_lto_module_to_llvm,
submit_post_lto_module_to_llvm};
use {MemFlags, CrateInfo};
use callee;
use rustc_mir::monomorphize::item::DefPathBasedNames;
@ -556,7 +558,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
backend: B,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
rx: mpsc::Receiver<Box<dyn Any + Send>>
) -> B::OngoingCodegen {
) -> OngoingCodegen<B> {
check_for_rustc_errors_attr(tcx);
@ -590,19 +592,20 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
// Skip crate items and just output metadata in -Z no-codegen mode.
if tcx.sess.opts.debugging_opts.no_codegen ||
!tcx.sess.opts.output_types.should_codegen() {
let ongoing_codegen = backend.start_async_codegen(
let ongoing_codegen = start_async_codegen(
backend,
tcx,
time_graph,
metadata,
rx,
1);
backend.submit_pre_codegened_module_to_backend(&ongoing_codegen, tcx, metadata_module);
backend.codegen_finished(&ongoing_codegen, tcx);
ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module);
ongoing_codegen.codegen_finished(tcx);
assert_and_save_dep_graph(tcx);
backend.check_for_errors(&ongoing_codegen, tcx.sess);
ongoing_codegen.check_for_errors(tcx.sess);
return ongoing_codegen;
}
@ -623,7 +626,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
}
}
let ongoing_codegen = backend.start_async_codegen(
let ongoing_codegen = start_async_codegen(
backend.clone(),
tcx,
time_graph.clone(),
metadata,
@ -667,10 +671,10 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
};
if let Some(allocator_module) = allocator_module {
backend.submit_pre_codegened_module_to_backend(&ongoing_codegen, tcx, allocator_module);
ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, allocator_module);
}
backend.submit_pre_codegened_module_to_backend(&ongoing_codegen, tcx, metadata_module);
ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module);
// We sort the codegen units by size. This way we can schedule work for LLVM
// a bit more efficiently.
@ -684,8 +688,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
let mut all_stats = Stats::default();
for cgu in codegen_units.into_iter() {
backend.wait_for_signal_to_codegen_item(&ongoing_codegen);
backend.check_for_errors(&ongoing_codegen, tcx.sess);
ongoing_codegen.wait_for_signal_to_codegen_item();
ongoing_codegen.check_for_errors(tcx.sess);
let cgu_reuse = determine_cgu_reuse(tcx, &cgu);
tcx.sess.cgu_reuse_tracker.set_actual_reuse(&cgu.name().as_str(), cgu_reuse);
@ -704,14 +708,14 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
false
}
CguReuse::PreLto => {
backend.submit_pre_lto_module_to_backend(tcx, CachedModuleCodegen {
submit_pre_lto_module_to_llvm(&backend, tcx, CachedModuleCodegen {
name: cgu.name().to_string(),
source: cgu.work_product(tcx),
});
true
}
CguReuse::PostLto => {
backend.submit_post_lto_module_to_backend(tcx, CachedModuleCodegen {
submit_post_lto_module_to_llvm(&backend, tcx, CachedModuleCodegen {
name: cgu.name().to_string(),
source: cgu.work_product(tcx),
});
@ -720,7 +724,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
};
}
backend.codegen_finished(&ongoing_codegen, tcx);
ongoing_codegen.codegen_finished(tcx);
// Since the main thread is sometimes blocked during codegen, we keep track
// -Ztime-passes output manually.
@ -754,7 +758,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
}
}
backend.check_for_errors(&ongoing_codegen, tcx.sess);
ongoing_codegen.check_for_errors(tcx.sess);
assert_and_save_dep_graph(tcx);
ongoing_codegen.into_inner()
@ -777,24 +781,24 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
/// If you see this comment in the code, then it means that this workaround
/// worked! We may yet one day track down the mysterious cause of that
/// segfault...
struct AbortCodegenOnDrop<B: ExtraBackendMethods>(Option<B::OngoingCodegen>);
struct AbortCodegenOnDrop<B: ExtraBackendMethods>(Option<OngoingCodegen<B>>);
impl<B: ExtraBackendMethods> AbortCodegenOnDrop<B> {
fn into_inner(mut self) -> B::OngoingCodegen {
fn into_inner(mut self) -> OngoingCodegen<B> {
self.0.take().unwrap()
}
}
impl<B: ExtraBackendMethods> Deref for AbortCodegenOnDrop<B> {
type Target = B::OngoingCodegen;
type Target = OngoingCodegen<B>;
fn deref(&self) -> &B::OngoingCodegen {
fn deref(&self) -> &OngoingCodegen<B> {
self.0.as_ref().unwrap()
}
}
impl<B: ExtraBackendMethods> DerefMut for AbortCodegenOnDrop<B> {
fn deref_mut(&mut self) -> &mut B::OngoingCodegen {
fn deref_mut(&mut self) -> &mut OngoingCodegen<B> {
self.0.as_mut().unwrap()
}
}
@ -802,7 +806,7 @@ impl<B: ExtraBackendMethods> DerefMut for AbortCodegenOnDrop<B> {
impl<B: ExtraBackendMethods> Drop for AbortCodegenOnDrop<B> {
fn drop(&mut self) {
if let Some(codegen) = self.0.take() {
B::codegen_aborted(codegen);
codegen.codegen_aborted();
}
}
}

View File

@ -11,18 +11,16 @@
use rustc::ty::layout::{HasTyCtxt, LayoutOf, TyLayout};
use rustc::ty::Ty;
use super::write::WriteBackendMethods;
use super::CodegenObject;
use rustc::middle::allocator::AllocatorKind;
use rustc::middle::cstore::EncodedMetadata;
use rustc::mir::mono::Stats;
use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc::util::time_graph::TimeGraph;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use std::any::Any;
use std::sync::mpsc::Receiver;
use std::sync::Arc;
use syntax_pos::symbol::InternedString;
use {CachedModuleCodegen, ModuleCodegen};
pub trait BackendTypes {
type Value: CodegenObject;
@ -43,10 +41,7 @@ impl<'tcx, T> Backend<'tcx> for T where
Self: BackendTypes + HasTyCtxt<'tcx> + LayoutOf<Ty = Ty<'tcx>, TyLayout = TyLayout<'tcx>>
{}
pub trait ExtraBackendMethods: CodegenBackend {
type Module;
type OngoingCodegen;
pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send {
fn new_metadata(&self, sess: &Session, mod_name: &str) -> Self::Module;
fn write_metadata<'b, 'gcx>(
&self,
@ -54,30 +49,18 @@ pub trait ExtraBackendMethods: CodegenBackend {
metadata: &Self::Module,
) -> EncodedMetadata;
fn codegen_allocator(&self, tcx: TyCtxt, mods: &Self::Module, kind: AllocatorKind);
fn start_async_codegen(
&self,
tcx: TyCtxt,
time_graph: Option<TimeGraph>,
metadata: EncodedMetadata,
coordinator_receive: Receiver<Box<dyn Any + Send>>,
total_cgus: usize,
) -> Self::OngoingCodegen;
fn submit_pre_codegened_module_to_backend(
&self,
codegen: &Self::OngoingCodegen,
tcx: TyCtxt,
module: ModuleCodegen<Self::Module>,
);
fn submit_pre_lto_module_to_backend(&self, tcx: TyCtxt, module: CachedModuleCodegen);
fn submit_post_lto_module_to_backend(&self, tcx: TyCtxt, module: CachedModuleCodegen);
fn codegen_aborted(codegen: Self::OngoingCodegen);
fn codegen_finished(&self, codegen: &Self::OngoingCodegen, tcx: TyCtxt);
fn check_for_errors(&self, codegen: &Self::OngoingCodegen, sess: &Session);
fn wait_for_signal_to_codegen_item(&self, codegen: &Self::OngoingCodegen);
fn compile_codegen_unit<'a, 'tcx: 'a>(
&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
cgu_name: InternedString,
) -> Stats;
// If find_features is true this won't access `sess.crate_types` by assuming
// that `is_pie_binary` is false. When we discover LLVM target features
// `sess.crate_types` is uninitialized so we cannot access it.
fn target_machine_factory(
&self,
sess: &Session,
find_features: bool,
) -> Arc<dyn Fn() -> Result<Self::TargetMachine, String> + Send + Sync>;
fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str;
}

View File

@ -35,6 +35,7 @@ mod intrinsic;
mod misc;
mod statics;
mod type_;
mod write;
pub use self::abi::{AbiBuilderMethods, AbiMethods};
pub use self::asm::{AsmBuilderMethods, AsmMethods};
@ -49,6 +50,7 @@ pub use self::statics::StaticMethods;
pub use self::type_::{
ArgTypeMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods,
};
pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
use std::fmt;

View File

@ -0,0 +1,72 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
use back::write::{CodegenContext, ModuleConfig};
use {CompiledModule, ModuleCodegen};
use rustc::dep_graph::WorkProduct;
use rustc::util::time_graph::Timeline;
use rustc_errors::{FatalError, Handler};
pub trait WriteBackendMethods: 'static + Sized + Clone {
type Module: Send + Sync;
type TargetMachine: Clone;
type ModuleBuffer: ModuleBufferMethods;
type Context: ?Sized;
type ThinData: Send + Sync;
type ThinBuffer: ThinBufferMethods;
/// Performs LTO, which in the case of full LTO means merging all modules into
/// a single one and returning it for further optimizing. For ThinLTO, it will
/// do the global analysis necessary and return two lists, one of the modules
/// the need optimization and another for modules that can simply be copied over
/// from the incr. comp. cache.
fn run_lto(
cgcx: &CodegenContext<Self>,
modules: Vec<ModuleCodegen<Self::Module>>,
cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
timeline: &mut Timeline,
) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError>;
fn print_pass_timings(&self);
unsafe fn optimize(
cgcx: &CodegenContext<Self>,
diag_handler: &Handler,
module: &ModuleCodegen<Self::Module>,
config: &ModuleConfig,
timeline: &mut Timeline,
) -> Result<(), FatalError>;
unsafe fn optimize_thin(
cgcx: &CodegenContext<Self>,
thin: &mut ThinModule<Self>,
timeline: &mut Timeline,
) -> Result<ModuleCodegen<Self::Module>, FatalError>;
unsafe fn codegen(
cgcx: &CodegenContext<Self>,
diag_handler: &Handler,
module: ModuleCodegen<Self::Module>,
config: &ModuleConfig,
timeline: &mut Timeline,
) -> Result<CompiledModule, FatalError>;
fn run_lto_pass_manager(
cgcx: &CodegenContext<Self>,
llmod: &ModuleCodegen<Self::Module>,
config: &ModuleConfig,
thin: bool,
);
}
pub trait ThinBufferMethods: Send + Sync {
fn data(&self) -> &[u8];
}
pub trait ModuleBufferMethods: Send + Sync {
fn data(&self) -> &[u8];
}

View File

@ -39,7 +39,16 @@ extern crate syntax_pos;
extern crate rustc_incremental;
extern crate rustc_codegen_utils;
extern crate rustc_data_structures;
extern crate rustc_allocator;
extern crate rustc_fs_util;
extern crate serialize;
extern crate rustc_errors;
extern crate rustc_demangle;
extern crate cc;
extern crate libc;
extern crate jobserver;
extern crate memmap;
extern crate num_cpus;
use std::path::PathBuf;
use rustc::dep_graph::WorkProduct;
@ -48,7 +57,9 @@ use rustc::middle::lang_items::LangItem;
use rustc::hir::def_id::CrateNum;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::svh::Svh;
use rustc::middle::cstore::{LibSource, CrateSource, NativeLibrary};
use syntax_pos::symbol::Symbol;
// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
@ -63,6 +74,7 @@ pub mod callee;
pub mod glue;
pub mod meth;
pub mod mono_item;
pub mod back;
pub struct ModuleCodegen<M> {
/// The name of the module. When the crate may be saved between
@ -159,4 +171,17 @@ pub struct CrateInfo {
pub missing_lang_items: FxHashMap<CrateNum, Vec<LangItem>>,
}
pub struct CodegenResults {
pub crate_name: Symbol,
pub modules: Vec<CompiledModule>,
pub allocator_module: Option<CompiledModule>,
pub metadata_module: CompiledModule,
pub crate_hash: Svh,
pub metadata: rustc::middle::cstore::EncodedMetadata,
pub windows_subsystem: Option<String>,
pub linker_info: back::linker::LinkerInfo,
pub crate_info: CrateInfo,
}
__build_diagnostic_array! { librustc_codegen_ssa, DIAGNOSTICS }

View File

@ -13,11 +13,9 @@ test = false
flate2 = "1.0"
log = "0.4"
serialize = { path = "../libserialize" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
rustc = { path = "../librustc" }
rustc_allocator = { path = "../librustc_allocator" }
rustc_target = { path = "../librustc_target" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_metadata = { path = "../librustc_metadata" }

View File

@ -31,10 +31,8 @@ extern crate flate2;
#[macro_use]
extern crate log;
extern crate serialize;
#[macro_use]
extern crate rustc;
extern crate rustc_allocator;
extern crate rustc_target;
extern crate rustc_metadata;
extern crate rustc_mir;
@ -43,16 +41,10 @@ extern crate syntax;
extern crate syntax_pos;
#[macro_use] extern crate rustc_data_structures;
use std::path::PathBuf;
use rustc::session::Session;
use rustc::ty::TyCtxt;
pub mod command;
pub mod link;
pub mod linker;
pub mod codegen_backend;
pub mod symbol_export;
pub mod symbol_names;
pub mod symbol_names_test;
@ -70,27 +62,4 @@ pub fn check_for_rustc_errors_attr(tcx: TyCtxt) {
}
}
pub fn find_library(name: &str, search_paths: &[PathBuf], sess: &Session)
-> PathBuf {
// On Windows, static libraries sometimes show up as libfoo.a and other
// times show up as foo.lib
let oslibname = format!("{}{}{}",
sess.target.target.options.staticlib_prefix,
name,
sess.target.target.options.staticlib_suffix);
let unixlibname = format!("lib{}.a", name);
for path in search_paths {
debug!("looking for {} inside {:?}", name, path);
let test = path.join(&oslibname);
if test.exists() { return test }
if oslibname != unixlibname {
let test = path.join(&unixlibname);
if test.exists() { return test }
}
}
sess.fatal(&format!("could not find native static library `{}`, \
perhaps an -L flag is missing?", name));
}
__build_diagnostic_array! { librustc_codegen_utils, DIAGNOSTICS }