mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Separating the back folder between backend-agnostic and LLVM-specific code
This commit is contained in:
parent
b25b804013
commit
b9e5cf99a9
@ -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",
|
||||
]
|
||||
|
@ -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 {}: {}",
|
||||
|
@ -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
|
||||
|
@ -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
@ -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>(
|
||||
|
@ -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 }
|
||||
|
@ -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"
|
||||
|
36
src/librustc_codegen_ssa/back/archive.rs
Normal file
36
src/librustc_codegen_ssa/back/archive.rs
Normal 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));
|
||||
}
|
208
src/librustc_codegen_ssa/back/link.rs
Normal file
208
src/librustc_codegen_ssa/back/link.rs
Normal 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");
|
||||
}
|
@ -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
|
||||
}
|
122
src/librustc_codegen_ssa/back/lto.rs
Normal file
122
src/librustc_codegen_ssa/back/lto.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
17
src/librustc_codegen_ssa/back/mod.rs
Normal file
17
src/librustc_codegen_ssa/back/mod.rs
Normal 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;
|
1843
src/librustc_codegen_ssa/back/write.rs
Normal file
1843
src/librustc_codegen_ssa/back/write.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
72
src/librustc_codegen_ssa/interfaces/write.rs
Normal file
72
src/librustc_codegen_ssa/interfaces/write.rs
Normal 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];
|
||||
}
|
@ -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 }
|
||||
|
@ -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" }
|
||||
|
@ -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 }
|
||||
|
Loading…
Reference in New Issue
Block a user