mirror of https://github.com/rust-lang/rust.git
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]]
|
[[package]]
|
||||||
name = "rustc_codegen_ssa"
|
name = "rustc_codegen_ssa"
|
||||||
version = "0.0.0"
|
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]]
|
[[package]]
|
||||||
name = "rustc_codegen_utils"
|
name = "rustc_codegen_utils"
|
||||||
|
@ -2137,13 +2143,11 @@ dependencies = [
|
||||||
"flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc 0.0.0",
|
"rustc 0.0.0",
|
||||||
"rustc_allocator 0.0.0",
|
|
||||||
"rustc_data_structures 0.0.0",
|
"rustc_data_structures 0.0.0",
|
||||||
"rustc_incremental 0.0.0",
|
"rustc_incremental 0.0.0",
|
||||||
"rustc_metadata 0.0.0",
|
"rustc_metadata 0.0.0",
|
||||||
"rustc_mir 0.0.0",
|
"rustc_mir 0.0.0",
|
||||||
"rustc_target 0.0.0",
|
"rustc_target 0.0.0",
|
||||||
"serialize 0.0.0",
|
|
||||||
"syntax 0.0.0",
|
"syntax 0.0.0",
|
||||||
"syntax_pos 0.0.0",
|
"syntax_pos 0.0.0",
|
||||||
]
|
]
|
||||||
|
|
|
@ -18,6 +18,7 @@ use std::ptr;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use back::bytecode::RLIB_BYTECODE_EXTENSION;
|
use back::bytecode::RLIB_BYTECODE_EXTENSION;
|
||||||
|
use rustc_codegen_ssa::back::archive::find_library;
|
||||||
use libc;
|
use libc;
|
||||||
use llvm::archive_ro::{ArchiveRO, Child};
|
use llvm::archive_ro::{ArchiveRO, Child};
|
||||||
use llvm::{self, ArchiveKind};
|
use llvm::{self, ArchiveKind};
|
||||||
|
@ -52,7 +53,6 @@ enum Addition {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn is_relevant_child(c: &Child) -> bool {
|
fn is_relevant_child(c: &Child) -> bool {
|
||||||
match c.name() {
|
match c.name() {
|
||||||
Some(name) => !name.contains("SYMDEF"),
|
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
|
/// Adds all of the contents of a native library to this archive. This will
|
||||||
/// search in the relevant locations for a library named `name`.
|
/// search in the relevant locations for a library named `name`.
|
||||||
pub fn add_native_library(&mut self, name: &str) {
|
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.config.sess);
|
||||||
self.add_archive(&location, |_| false).unwrap_or_else(|e| {
|
self.add_archive(&location, |_| false).unwrap_or_else(|e| {
|
||||||
self.config.sess.fatal(&format!("failed to add native library {}: {}",
|
self.config.sess.fatal(&format!("failed to add native library {}: {}",
|
||||||
|
|
|
@ -9,9 +9,12 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use back::wasm;
|
use back::wasm;
|
||||||
use cc::windows_registry;
|
|
||||||
use super::archive::{ArchiveBuilder, ArchiveConfig};
|
use super::archive::{ArchiveBuilder, ArchiveConfig};
|
||||||
use super::bytecode::RLIB_BYTECODE_EXTENSION;
|
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::RPathConfig;
|
||||||
use super::rpath;
|
use super::rpath;
|
||||||
use metadata::METADATA_FILENAME;
|
use metadata::METADATA_FILENAME;
|
||||||
|
@ -20,18 +23,15 @@ use rustc::session::config::{RUST_CGU_EXT, Lto};
|
||||||
use rustc::session::filesearch;
|
use rustc::session::filesearch;
|
||||||
use rustc::session::search_paths::PathKind;
|
use rustc::session::search_paths::PathKind;
|
||||||
use rustc::session::Session;
|
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::middle::dependency_format::Linkage;
|
||||||
use rustc_codegen_ssa::CrateInfo;
|
use rustc_codegen_ssa::CodegenResults;
|
||||||
use CodegenResults;
|
|
||||||
use rustc::util::common::time;
|
use rustc::util::common::time;
|
||||||
use rustc_fs_util::fix_windows_verbatim_for_gcc;
|
use rustc_fs_util::fix_windows_verbatim_for_gcc;
|
||||||
use rustc::hir::def_id::CrateNum;
|
use rustc::hir::def_id::CrateNum;
|
||||||
use tempfile::{Builder as TempFileBuilder, TempDir};
|
use tempfile::{Builder as TempFileBuilder, TempDir};
|
||||||
use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor};
|
use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor};
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_codegen_utils::linker::Linker;
|
|
||||||
use rustc_codegen_utils::command::Command;
|
|
||||||
use context::get_reloc_model;
|
use context::get_reloc_model;
|
||||||
use llvm;
|
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,
|
invalid_output_for_target, filename_for_metadata,
|
||||||
out_filename, check_file_is_writeable};
|
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
|
/// Perform the linkage portion of the compilation phase. This will generate all
|
||||||
/// of the requested outputs for this compilation session.
|
/// of the requested outputs for this compilation session.
|
||||||
|
@ -215,60 +152,6 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
|
||||||
false
|
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,
|
fn link_binary_output(sess: &Session,
|
||||||
codegen_results: &CodegenResults,
|
codegen_results: &CodegenResults,
|
||||||
crate_type: config::CrateType,
|
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
|
/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
|
||||||
/// directory being searched for `extern crate` (observing an incomplete file).
|
/// directory being searched for `extern crate` (observing an incomplete file).
|
||||||
/// The returned path is the temporary file containing the complete metadata.
|
/// The returned path is the temporary file containing the complete metadata.
|
||||||
fn emit_metadata<'a>(sess: &'a Session, codegen_results: &CodegenResults, tmpdir: &TempDir)
|
fn emit_metadata<'a>(
|
||||||
-> PathBuf {
|
sess: &'a Session,
|
||||||
|
codegen_results: &CodegenResults,
|
||||||
|
tmpdir: &TempDir
|
||||||
|
) -> PathBuf {
|
||||||
let out_filename = tmpdir.path().join(METADATA_FILENAME);
|
let out_filename = tmpdir.path().join(METADATA_FILENAME);
|
||||||
let result = fs::write(&out_filename, &codegen_results.metadata.raw_data);
|
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
|
// Create a dynamic library or executable
|
||||||
//
|
//
|
||||||
// This will invoke the system linker/cc to create the resulting file. This
|
// This will invoke the system linker/cc to create the resulting file. This
|
||||||
|
|
|
@ -9,12 +9,14 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION};
|
use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION};
|
||||||
use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
|
use rustc_codegen_ssa::back::symbol_export;
|
||||||
use back::write::{self, DiagnosticHandlers, pre_lto_bitcode_filename};
|
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 errors::{FatalError, Handler};
|
||||||
use llvm::archive_ro::ArchiveRO;
|
use llvm::archive_ro::ArchiveRO;
|
||||||
use llvm::{self, True, False};
|
use llvm::{self, True, False};
|
||||||
use memmap;
|
|
||||||
use rustc::dep_graph::WorkProduct;
|
use rustc::dep_graph::WorkProduct;
|
||||||
use rustc::dep_graph::cgu_reuse_tracker::CguReuse;
|
use rustc::dep_graph::cgu_reuse_tracker::CguReuse;
|
||||||
use rustc::hir::def_id::LOCAL_CRATE;
|
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::session::config::{self, Lto};
|
||||||
use rustc::util::common::time_ext;
|
use rustc::util::common::time_ext;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_codegen_utils::symbol_export;
|
|
||||||
use time_graph::Timeline;
|
use time_graph::Timeline;
|
||||||
use ModuleLlvm;
|
use {ModuleLlvm, LlvmCodegenBackend};
|
||||||
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
|
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
|
||||||
|
|
||||||
use libc;
|
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
|
/// 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
|
/// 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
|
/// 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
|
/// the need optimization and another for modules that can simply be copied over
|
||||||
/// from the incr. comp. cache.
|
/// from the incr. comp. cache.
|
||||||
pub(crate) fn run(cgcx: &CodegenContext,
|
pub(crate) fn run(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||||
modules: Vec<ModuleCodegen<ModuleLlvm>>,
|
modules: Vec<ModuleCodegen<ModuleLlvm>>,
|
||||||
cached_modules: Vec<(SerializedModule, WorkProduct)>,
|
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
|
||||||
timeline: &mut Timeline)
|
timeline: &mut Timeline)
|
||||||
-> Result<(Vec<LtoModuleCodegen>, Vec<WorkProduct>), FatalError>
|
-> Result<(Vec<LtoModuleCodegen<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError>
|
||||||
{
|
{
|
||||||
let diag_handler = cgcx.create_diag_handler();
|
let diag_handler = cgcx.create_diag_handler();
|
||||||
let export_threshold = match cgcx.lto {
|
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,
|
diag_handler: &Handler,
|
||||||
mut modules: Vec<ModuleCodegen<ModuleLlvm>>,
|
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],
|
symbol_white_list: &[*const libc::c_char],
|
||||||
timeline: &mut Timeline)
|
timeline: &mut Timeline)
|
||||||
-> Result<Vec<LtoModuleCodegen>, FatalError>
|
-> Result<Vec<LtoModuleCodegen<LlvmCodegenBackend>>, FatalError>
|
||||||
{
|
{
|
||||||
info!("going for a fat lto");
|
info!("going for a fat lto");
|
||||||
|
|
||||||
|
@ -303,7 +249,7 @@ fn fat_lto(cgcx: &CodegenContext,
|
||||||
serialized_bitcode.push(bc_decoded);
|
serialized_bitcode.push(bc_decoded);
|
||||||
}
|
}
|
||||||
drop(linker);
|
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
|
// Internalize everything that *isn't* in our whitelist to help strip out
|
||||||
// more modules and such
|
// more modules and such
|
||||||
|
@ -312,14 +258,14 @@ fn fat_lto(cgcx: &CodegenContext,
|
||||||
llvm::LLVMRustRunRestrictionPass(llmod,
|
llvm::LLVMRustRunRestrictionPass(llmod,
|
||||||
ptr as *const *const libc::c_char,
|
ptr as *const *const libc::c_char,
|
||||||
symbol_white_list.len() as libc::size_t);
|
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 {
|
if cgcx.no_landing_pads {
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
|
llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
|
||||||
}
|
}
|
||||||
cgcx.save_temp_bitcode(&module, "lto.after-nounwind");
|
save_temp_bitcode(&cgcx, &module, "lto.after-nounwind");
|
||||||
}
|
}
|
||||||
timeline.record("passes");
|
timeline.record("passes");
|
||||||
}
|
}
|
||||||
|
@ -386,14 +332,14 @@ impl Drop for Linker<'a> {
|
||||||
/// calculating the *index* for ThinLTO. This index will then be shared amongst
|
/// calculating the *index* for ThinLTO. This index will then be shared amongst
|
||||||
/// all of the `LtoModuleCodegen` units returned below and destroyed once
|
/// all of the `LtoModuleCodegen` units returned below and destroyed once
|
||||||
/// they all go out of scope.
|
/// they all go out of scope.
|
||||||
fn thin_lto(cgcx: &CodegenContext,
|
fn thin_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||||
diag_handler: &Handler,
|
diag_handler: &Handler,
|
||||||
modules: Vec<ModuleCodegen<ModuleLlvm>>,
|
modules: Vec<ModuleCodegen<ModuleLlvm>>,
|
||||||
serialized_modules: Vec<(SerializedModule, CString)>,
|
serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
|
||||||
cached_modules: Vec<(SerializedModule, WorkProduct)>,
|
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
|
||||||
symbol_white_list: &[*const libc::c_char],
|
symbol_white_list: &[*const libc::c_char],
|
||||||
timeline: &mut Timeline)
|
timeline: &mut Timeline)
|
||||||
-> Result<(Vec<LtoModuleCodegen>, Vec<WorkProduct>), FatalError>
|
-> Result<(Vec<LtoModuleCodegen<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError>
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
info!("going for that thin, thin LTO");
|
info!("going for that thin, thin LTO");
|
||||||
|
@ -556,9 +502,8 @@ fn thin_lto(cgcx: &CodegenContext,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_pass_manager(cgcx: &CodegenContext,
|
pub(crate) fn run_pass_manager(cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||||
tm: &llvm::TargetMachine,
|
module: &ModuleCodegen<ModuleLlvm>,
|
||||||
llmod: &llvm::Module,
|
|
||||||
config: &ModuleConfig,
|
config: &ModuleConfig,
|
||||||
thin: bool) {
|
thin: bool) {
|
||||||
// Now we have one massive module inside of llmod. Time to run the
|
// 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");
|
debug!("running the pass manager");
|
||||||
unsafe {
|
unsafe {
|
||||||
let pm = llvm::LLVMCreatePassManager();
|
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 {
|
if config.verify_llvm_ir {
|
||||||
let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _);
|
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
|
// Note that in general this shouldn't matter too much as you typically
|
||||||
// only turn on ThinLTO when you're compiling with optimizations
|
// only turn on ThinLTO when you're compiling with optimizations
|
||||||
// otherwise.
|
// 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 {
|
let opt_level = match opt_level {
|
||||||
llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less,
|
llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less,
|
||||||
level => level,
|
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 {
|
if thin {
|
||||||
llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm);
|
llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm);
|
||||||
} else {
|
} else {
|
||||||
|
@ -615,29 +561,14 @@ fn run_pass_manager(cgcx: &CodegenContext,
|
||||||
llvm::LLVMRustAddPass(pm, pass.unwrap());
|
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);
|
llvm::LLVMDisposePassManager(pm);
|
||||||
}
|
}
|
||||||
debug!("lto done");
|
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);
|
pub struct ModuleBuffer(&'static mut llvm::ModuleBuffer);
|
||||||
|
|
||||||
unsafe impl Send for ModuleBuffer {}
|
unsafe impl Send for ModuleBuffer {}
|
||||||
|
@ -649,8 +580,10 @@ impl ModuleBuffer {
|
||||||
llvm::LLVMRustModuleBufferCreate(m)
|
llvm::LLVMRustModuleBufferCreate(m)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn data(&self) -> &[u8] {
|
impl ModuleBufferMethods for ModuleBuffer {
|
||||||
|
fn data(&self) -> &[u8] {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = llvm::LLVMRustModuleBufferPtr(self.0);
|
let ptr = llvm::LLVMRustModuleBufferPtr(self.0);
|
||||||
let len = llvm::LLVMRustModuleBufferLen(self.0);
|
let len = llvm::LLVMRustModuleBufferLen(self.0);
|
||||||
|
@ -665,19 +598,7 @@ impl Drop for ModuleBuffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ThinModule {
|
pub struct ThinData(&'static mut llvm::ThinLTOData);
|
||||||
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);
|
|
||||||
|
|
||||||
unsafe impl Send for ThinData {}
|
unsafe impl Send for ThinData {}
|
||||||
unsafe impl Sync for ThinData {}
|
unsafe impl Sync for ThinData {}
|
||||||
|
@ -702,8 +623,10 @@ impl ThinBuffer {
|
||||||
ThinBuffer(buffer)
|
ThinBuffer(buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn data(&self) -> &[u8] {
|
impl ThinBufferMethods for ThinBuffer {
|
||||||
|
fn data(&self) -> &[u8] {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = llvm::LLVMRustThinLTOBufferPtr(self.0) as *const _;
|
let ptr = llvm::LLVMRustThinLTOBufferPtr(self.0) as *const _;
|
||||||
let len = llvm::LLVMRustThinLTOBufferLen(self.0);
|
let len = llvm::LLVMRustThinLTOBufferLen(self.0);
|
||||||
|
@ -720,161 +643,142 @@ impl Drop for ThinBuffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ThinModule {
|
pub unsafe fn optimize_thin_module(
|
||||||
fn name(&self) -> &str {
|
thin_module: &mut ThinModule<LlvmCodegenBackend>,
|
||||||
self.shared.module_names[self.idx].to_str().unwrap()
|
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 {
|
// Right now the implementation we've got only works over serialized
|
||||||
// Yes, that's correct, we're using the size of the bytecode as an
|
// modules, so we create a fresh new LLVM context and parse the module
|
||||||
// indicator for how costly this codegen unit is.
|
// into that context. One day, however, we may do this for upstream
|
||||||
self.data().len() as u64
|
// crates but for locally codegened modules we may be able to reuse
|
||||||
}
|
// that LLVM Context and Module.
|
||||||
|
let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
|
||||||
fn data(&self) -> &[u8] {
|
let llmod_raw = llvm::LLVMRustParseBitcodeForThinLTO(
|
||||||
let a = self.shared.thin_buffers.get(self.idx).map(|b| b.data());
|
llcx,
|
||||||
a.unwrap_or_else(|| {
|
thin_module.data().as_ptr(),
|
||||||
let len = self.shared.thin_buffers.len();
|
thin_module.data().len(),
|
||||||
self.shared.serialized_modules[self.idx - len].data()
|
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)
|
||||||
unsafe fn optimize(&mut self, cgcx: &CodegenContext, timeline: &mut Timeline)
|
})? as *const _;
|
||||||
-> Result<ModuleCodegen<ModuleLlvm>, FatalError>
|
let module = ModuleCodegen {
|
||||||
{
|
module_llvm: ModuleLlvm {
|
||||||
let diag_handler = cgcx.create_diag_handler();
|
llmod_raw,
|
||||||
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(
|
|
||||||
llcx,
|
llcx,
|
||||||
self.data().as_ptr(),
|
tm,
|
||||||
self.data().len(),
|
},
|
||||||
self.shared.module_names[self.idx].as_ptr(),
|
name: thin_module.name().to_string(),
|
||||||
).ok_or_else(|| {
|
kind: ModuleKind::Regular,
|
||||||
let msg = "failed to parse bitcode for thin LTO module";
|
};
|
||||||
write::llvm_err(&diag_handler, msg)
|
{
|
||||||
})? as *const _;
|
let llmod = module.module_llvm.llmod();
|
||||||
let module = ModuleCodegen {
|
save_temp_bitcode(&cgcx, &module, "thin-lto-input");
|
||||||
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");
|
|
||||||
|
|
||||||
// Before we do much else find the "main" `DICompileUnit` that we'll be
|
// 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
|
// 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
|
// in a way we're not ready for, so generate an ICE by returning
|
||||||
// an error.
|
// an error.
|
||||||
let mut cu1 = ptr::null_mut();
|
let mut cu1 = ptr::null_mut();
|
||||||
let mut cu2 = ptr::null_mut();
|
let mut cu2 = ptr::null_mut();
|
||||||
llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2);
|
llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2);
|
||||||
if !cu2.is_null() {
|
if !cu2.is_null() {
|
||||||
let msg = "multiple source DICompileUnits found";
|
let msg = "multiple source DICompileUnits found";
|
||||||
return Err(write::llvm_err(&diag_handler, msg))
|
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)]
|
#[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 rustc_codegen_ssa::base::maybe_create_entry_wrapper;
|
||||||
use super::LlvmCodegenBackend;
|
use super::LlvmCodegenBackend;
|
||||||
|
|
||||||
use back::write;
|
|
||||||
use llvm;
|
use llvm;
|
||||||
use metadata;
|
use metadata;
|
||||||
use rustc::mir::mono::{Linkage, Visibility, Stats};
|
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_data_structures::small_c_str::SmallCStr;
|
||||||
|
|
||||||
use rustc_codegen_ssa::interfaces::*;
|
use rustc_codegen_ssa::interfaces::*;
|
||||||
|
use rustc_codegen_ssa::back::write::submit_codegened_module_to_llvm;
|
||||||
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
@ -53,7 +53,7 @@ use rustc::hir::CodegenFnAttrs;
|
||||||
use value::Value;
|
use value::Value;
|
||||||
|
|
||||||
|
|
||||||
pub(crate) fn write_metadata<'a, 'gcx>(
|
pub fn write_metadata<'a, 'gcx>(
|
||||||
tcx: TyCtxt<'a, 'gcx, 'gcx>,
|
tcx: TyCtxt<'a, 'gcx, 'gcx>,
|
||||||
llvm_module: &ModuleLlvm
|
llvm_module: &ModuleLlvm
|
||||||
) -> EncodedMetadata {
|
) -> 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 +
|
let cost = time_to_codegen.as_secs() * 1_000_000_000 +
|
||||||
time_to_codegen.subsec_nanos() as u64;
|
time_to_codegen.subsec_nanos() as u64;
|
||||||
|
|
||||||
write::submit_codegened_module_to_llvm(tcx,
|
submit_codegened_module_to_llvm(&LlvmCodegenBackend(()), tcx, module, cost);
|
||||||
module,
|
|
||||||
cost);
|
|
||||||
return stats;
|
return stats;
|
||||||
|
|
||||||
fn module_codegen<'ll, 'tcx>(
|
fn module_codegen<'ll, 'tcx>(
|
||||||
|
|
|
@ -68,15 +68,17 @@ extern crate tempfile;
|
||||||
extern crate memmap;
|
extern crate memmap;
|
||||||
|
|
||||||
use rustc_codegen_ssa::interfaces::*;
|
use rustc_codegen_ssa::interfaces::*;
|
||||||
use time_graph::TimeGraph;
|
use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig};
|
||||||
use std::sync::mpsc::Receiver;
|
use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinModule};
|
||||||
use back::write::{self, OngoingCodegen};
|
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 syntax_pos::symbol::InternedString;
|
||||||
use rustc::mir::mono::Stats;
|
use rustc::mir::mono::Stats;
|
||||||
|
|
||||||
pub use llvm_util::target_features;
|
pub use llvm_util::target_features;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::sync::mpsc;
|
use std::sync::{mpsc, Arc};
|
||||||
|
|
||||||
use rustc::dep_graph::DepGraph;
|
use rustc::dep_graph::DepGraph;
|
||||||
use rustc::middle::allocator::AllocatorKind;
|
use rustc::middle::allocator::AllocatorKind;
|
||||||
|
@ -87,9 +89,8 @@ use rustc::ty::{self, TyCtxt};
|
||||||
use rustc::util::time_graph;
|
use rustc::util::time_graph;
|
||||||
use rustc::util::profiling::ProfileCategory;
|
use rustc::util::profiling::ProfileCategory;
|
||||||
use rustc_mir::monomorphize;
|
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_codegen_utils::codegen_backend::CodegenBackend;
|
||||||
use rustc_data_structures::svh::Svh;
|
|
||||||
|
|
||||||
mod diagnostics;
|
mod diagnostics;
|
||||||
|
|
||||||
|
@ -127,12 +128,10 @@ mod type_;
|
||||||
mod type_of;
|
mod type_of;
|
||||||
mod value;
|
mod value;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct LlvmCodegenBackend(());
|
pub struct LlvmCodegenBackend(());
|
||||||
|
|
||||||
impl ExtraBackendMethods for LlvmCodegenBackend {
|
impl ExtraBackendMethods for LlvmCodegenBackend {
|
||||||
type Module = ModuleLlvm;
|
|
||||||
type OngoingCodegen = OngoingCodegen;
|
|
||||||
|
|
||||||
fn new_metadata(&self, sess: &Session, mod_name: &str) -> ModuleLlvm {
|
fn new_metadata(&self, sess: &Session, mod_name: &str) -> ModuleLlvm {
|
||||||
ModuleLlvm::new(sess, mod_name)
|
ModuleLlvm::new(sess, mod_name)
|
||||||
}
|
}
|
||||||
|
@ -143,45 +142,9 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
|
||||||
) -> EncodedMetadata {
|
) -> EncodedMetadata {
|
||||||
base::write_metadata(tcx, metadata)
|
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) {
|
fn codegen_allocator(&self, tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) {
|
||||||
unsafe { allocator::codegen(tcx, mods, kind) }
|
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>(
|
fn compile_codegen_unit<'a, 'tcx: 'a>(
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
@ -189,11 +152,85 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
|
||||||
) -> Stats {
|
) -> Stats {
|
||||||
base::compile_codegen_unit(tcx, cgu_name)
|
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 WriteBackendMethods for LlvmCodegenBackend {
|
||||||
impl !Sync 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 {
|
impl LlvmCodegenBackend {
|
||||||
pub fn new() -> Box<dyn CodegenBackend> {
|
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) {
|
fn init(&self, sess: &Session) {
|
||||||
llvm_util::init(sess); // Make sure llvm is inited
|
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) {
|
fn provide(&self, providers: &mut ty::query::Providers) {
|
||||||
rustc_codegen_utils::symbol_export::provide(providers);
|
|
||||||
rustc_codegen_utils::symbol_names::provide(providers);
|
rustc_codegen_utils::symbol_names::provide(providers);
|
||||||
|
rustc_codegen_ssa::back::symbol_export::provide(providers);
|
||||||
rustc_codegen_ssa::base::provide_both(providers);
|
rustc_codegen_ssa::base::provide_both(providers);
|
||||||
attributes::provide(providers);
|
attributes::provide(providers);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn provide_extern(&self, providers: &mut ty::query::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);
|
rustc_codegen_ssa::base::provide_both(providers);
|
||||||
attributes::provide_extern(providers);
|
attributes::provide_extern(providers);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn codegen_crate<'a, 'tcx>(
|
fn codegen_crate<'b, 'tcx>(
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'b, 'tcx, 'tcx>,
|
||||||
rx: mpsc::Receiver<Box<dyn Any + Send>>
|
rx: mpsc::Receiver<Box<dyn Any + Send>>
|
||||||
) -> Box<dyn Any> {
|
) -> Box<dyn Any> {
|
||||||
box rustc_codegen_ssa::base::codegen_crate(LlvmCodegenBackend(()), tcx, rx)
|
box rustc_codegen_ssa::base::codegen_crate(LlvmCodegenBackend(()), tcx, rx)
|
||||||
|
@ -282,12 +319,13 @@ impl CodegenBackend for LlvmCodegenBackend {
|
||||||
outputs: &OutputFilenames,
|
outputs: &OutputFilenames,
|
||||||
) -> Result<(), CompileIncomplete>{
|
) -> Result<(), CompileIncomplete>{
|
||||||
use rustc::util::common::time;
|
use rustc::util::common::time;
|
||||||
let (ongoing_codegen, work_products) =
|
let (codegen_results, work_products) =
|
||||||
ongoing_codegen.downcast::<::back::write::OngoingCodegen>()
|
ongoing_codegen.downcast::
|
||||||
|
<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
|
||||||
.expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
|
.expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
|
||||||
.join(sess);
|
.join(sess);
|
||||||
if sess.opts.debugging_opts.incremental_info {
|
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,
|
time(sess,
|
||||||
|
@ -305,14 +343,14 @@ impl CodegenBackend for LlvmCodegenBackend {
|
||||||
// This should produce either a finished executable or library.
|
// This should produce either a finished executable or library.
|
||||||
sess.profiler(|p| p.start_activity(ProfileCategory::Linking));
|
sess.profiler(|p| p.start_activity(ProfileCategory::Linking));
|
||||||
time(sess, "linking", || {
|
time(sess, "linking", || {
|
||||||
back::link::link_binary(sess, &ongoing_codegen,
|
back::link::link_binary(sess, &codegen_results,
|
||||||
outputs, &ongoing_codegen.crate_name.as_str());
|
outputs, &codegen_results.crate_name.as_str());
|
||||||
});
|
});
|
||||||
sess.profiler(|p| p.end_activity(ProfileCategory::Linking));
|
sess.profiler(|p| p.end_activity(ProfileCategory::Linking));
|
||||||
|
|
||||||
// Now that we won't touch anything in the incremental compilation directory
|
// Now that we won't touch anything in the incremental compilation directory
|
||||||
// any more, we can finalize it (which involves renaming it)
|
// 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(())
|
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 }
|
__build_diagnostic_array! { librustc_codegen_llvm, DIAGNOSTICS }
|
||||||
|
|
|
@ -9,3 +9,7 @@ path = "lib.rs"
|
||||||
test = false
|
test = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
cc = "1.0.1"
|
||||||
|
num_cpus = "1.0"
|
||||||
|
rustc-demangle = "0.1.4"
|
||||||
|
memmap = "0.6"
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
|
@ -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
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use super::symbol_export;
|
||||||
|
use super::command::Command;
|
||||||
|
use super::archive;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
|
@ -15,7 +19,6 @@ use std::io::prelude::*;
|
||||||
use std::io::{self, BufWriter};
|
use std::io::{self, BufWriter};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use command::Command;
|
|
||||||
use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
|
use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
|
||||||
use rustc::middle::dependency_format::Linkage;
|
use rustc::middle::dependency_format::Linkage;
|
||||||
use rustc::session::Session;
|
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
|
// -force_load is the macOS equivalent of --whole-archive, but it
|
||||||
// involves passing the full path to the library to link.
|
// involves passing the full path to the library to link.
|
||||||
self.linker_arg("-force_load");
|
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);
|
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> {
|
pub struct WasmLd<'a> {
|
||||||
cmd: Command,
|
cmd: Command,
|
||||||
sess: &'a Session,
|
sess: &'a Session,
|
||||||
|
@ -1075,3 +1048,32 @@ impl<'a> Linker for WasmLd<'a> {
|
||||||
// Do nothing for now
|
// 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
|
||||||
|
}
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
@ -39,6 +39,8 @@ use rustc::util::profiling::ProfileCategory;
|
||||||
use rustc::session::config::{self, EntryFnType, Lto};
|
use rustc::session::config::{self, EntryFnType, Lto};
|
||||||
use rustc::session::Session;
|
use rustc::session::Session;
|
||||||
use mir::place::PlaceRef;
|
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 {MemFlags, CrateInfo};
|
||||||
use callee;
|
use callee;
|
||||||
use rustc_mir::monomorphize::item::DefPathBasedNames;
|
use rustc_mir::monomorphize::item::DefPathBasedNames;
|
||||||
|
@ -556,7 +558,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
||||||
backend: B,
|
backend: B,
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
rx: mpsc::Receiver<Box<dyn Any + Send>>
|
rx: mpsc::Receiver<Box<dyn Any + Send>>
|
||||||
) -> B::OngoingCodegen {
|
) -> OngoingCodegen<B> {
|
||||||
|
|
||||||
check_for_rustc_errors_attr(tcx);
|
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.
|
// Skip crate items and just output metadata in -Z no-codegen mode.
|
||||||
if tcx.sess.opts.debugging_opts.no_codegen ||
|
if tcx.sess.opts.debugging_opts.no_codegen ||
|
||||||
!tcx.sess.opts.output_types.should_codegen() {
|
!tcx.sess.opts.output_types.should_codegen() {
|
||||||
let ongoing_codegen = backend.start_async_codegen(
|
let ongoing_codegen = start_async_codegen(
|
||||||
|
backend,
|
||||||
tcx,
|
tcx,
|
||||||
time_graph,
|
time_graph,
|
||||||
metadata,
|
metadata,
|
||||||
rx,
|
rx,
|
||||||
1);
|
1);
|
||||||
|
|
||||||
backend.submit_pre_codegened_module_to_backend(&ongoing_codegen, tcx, metadata_module);
|
ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module);
|
||||||
backend.codegen_finished(&ongoing_codegen, tcx);
|
ongoing_codegen.codegen_finished(tcx);
|
||||||
|
|
||||||
assert_and_save_dep_graph(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;
|
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,
|
tcx,
|
||||||
time_graph.clone(),
|
time_graph.clone(),
|
||||||
metadata,
|
metadata,
|
||||||
|
@ -667,10 +671,10 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(allocator_module) = allocator_module {
|
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
|
// We sort the codegen units by size. This way we can schedule work for LLVM
|
||||||
// a bit more efficiently.
|
// a bit more efficiently.
|
||||||
|
@ -684,8 +688,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
||||||
let mut all_stats = Stats::default();
|
let mut all_stats = Stats::default();
|
||||||
|
|
||||||
for cgu in codegen_units.into_iter() {
|
for cgu in codegen_units.into_iter() {
|
||||||
backend.wait_for_signal_to_codegen_item(&ongoing_codegen);
|
ongoing_codegen.wait_for_signal_to_codegen_item();
|
||||||
backend.check_for_errors(&ongoing_codegen, tcx.sess);
|
ongoing_codegen.check_for_errors(tcx.sess);
|
||||||
|
|
||||||
let cgu_reuse = determine_cgu_reuse(tcx, &cgu);
|
let cgu_reuse = determine_cgu_reuse(tcx, &cgu);
|
||||||
tcx.sess.cgu_reuse_tracker.set_actual_reuse(&cgu.name().as_str(), cgu_reuse);
|
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
|
false
|
||||||
}
|
}
|
||||||
CguReuse::PreLto => {
|
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(),
|
name: cgu.name().to_string(),
|
||||||
source: cgu.work_product(tcx),
|
source: cgu.work_product(tcx),
|
||||||
});
|
});
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
CguReuse::PostLto => {
|
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(),
|
name: cgu.name().to_string(),
|
||||||
source: cgu.work_product(tcx),
|
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
|
// Since the main thread is sometimes blocked during codegen, we keep track
|
||||||
// -Ztime-passes output manually.
|
// -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);
|
assert_and_save_dep_graph(tcx);
|
||||||
ongoing_codegen.into_inner()
|
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
|
/// 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
|
/// worked! We may yet one day track down the mysterious cause of that
|
||||||
/// segfault...
|
/// segfault...
|
||||||
struct AbortCodegenOnDrop<B: ExtraBackendMethods>(Option<B::OngoingCodegen>);
|
struct AbortCodegenOnDrop<B: ExtraBackendMethods>(Option<OngoingCodegen<B>>);
|
||||||
|
|
||||||
impl<B: ExtraBackendMethods> AbortCodegenOnDrop<B> {
|
impl<B: ExtraBackendMethods> AbortCodegenOnDrop<B> {
|
||||||
fn into_inner(mut self) -> B::OngoingCodegen {
|
fn into_inner(mut self) -> OngoingCodegen<B> {
|
||||||
self.0.take().unwrap()
|
self.0.take().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: ExtraBackendMethods> Deref for AbortCodegenOnDrop<B> {
|
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()
|
self.0.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: ExtraBackendMethods> DerefMut for AbortCodegenOnDrop<B> {
|
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()
|
self.0.as_mut().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -802,7 +806,7 @@ impl<B: ExtraBackendMethods> DerefMut for AbortCodegenOnDrop<B> {
|
||||||
impl<B: ExtraBackendMethods> Drop for AbortCodegenOnDrop<B> {
|
impl<B: ExtraBackendMethods> Drop for AbortCodegenOnDrop<B> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Some(codegen) = self.0.take() {
|
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::layout::{HasTyCtxt, LayoutOf, TyLayout};
|
||||||
use rustc::ty::Ty;
|
use rustc::ty::Ty;
|
||||||
|
|
||||||
|
use super::write::WriteBackendMethods;
|
||||||
use super::CodegenObject;
|
use super::CodegenObject;
|
||||||
use rustc::middle::allocator::AllocatorKind;
|
use rustc::middle::allocator::AllocatorKind;
|
||||||
use rustc::middle::cstore::EncodedMetadata;
|
use rustc::middle::cstore::EncodedMetadata;
|
||||||
use rustc::mir::mono::Stats;
|
use rustc::mir::mono::Stats;
|
||||||
use rustc::session::Session;
|
use rustc::session::Session;
|
||||||
use rustc::ty::TyCtxt;
|
use rustc::ty::TyCtxt;
|
||||||
use rustc::util::time_graph::TimeGraph;
|
|
||||||
use rustc_codegen_utils::codegen_backend::CodegenBackend;
|
use rustc_codegen_utils::codegen_backend::CodegenBackend;
|
||||||
use std::any::Any;
|
use std::sync::Arc;
|
||||||
use std::sync::mpsc::Receiver;
|
|
||||||
use syntax_pos::symbol::InternedString;
|
use syntax_pos::symbol::InternedString;
|
||||||
use {CachedModuleCodegen, ModuleCodegen};
|
|
||||||
|
|
||||||
pub trait BackendTypes {
|
pub trait BackendTypes {
|
||||||
type Value: CodegenObject;
|
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>>
|
Self: BackendTypes + HasTyCtxt<'tcx> + LayoutOf<Ty = Ty<'tcx>, TyLayout = TyLayout<'tcx>>
|
||||||
{}
|
{}
|
||||||
|
|
||||||
pub trait ExtraBackendMethods: CodegenBackend {
|
pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send {
|
||||||
type Module;
|
|
||||||
type OngoingCodegen;
|
|
||||||
|
|
||||||
fn new_metadata(&self, sess: &Session, mod_name: &str) -> Self::Module;
|
fn new_metadata(&self, sess: &Session, mod_name: &str) -> Self::Module;
|
||||||
fn write_metadata<'b, 'gcx>(
|
fn write_metadata<'b, 'gcx>(
|
||||||
&self,
|
&self,
|
||||||
|
@ -54,30 +49,18 @@ pub trait ExtraBackendMethods: CodegenBackend {
|
||||||
metadata: &Self::Module,
|
metadata: &Self::Module,
|
||||||
) -> EncodedMetadata;
|
) -> EncodedMetadata;
|
||||||
fn codegen_allocator(&self, tcx: TyCtxt, mods: &Self::Module, kind: AllocatorKind);
|
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>(
|
fn compile_codegen_unit<'a, 'tcx: 'a>(
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
cgu_name: InternedString,
|
cgu_name: InternedString,
|
||||||
) -> Stats;
|
) -> 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 misc;
|
||||||
mod statics;
|
mod statics;
|
||||||
mod type_;
|
mod type_;
|
||||||
|
mod write;
|
||||||
|
|
||||||
pub use self::abi::{AbiBuilderMethods, AbiMethods};
|
pub use self::abi::{AbiBuilderMethods, AbiMethods};
|
||||||
pub use self::asm::{AsmBuilderMethods, AsmMethods};
|
pub use self::asm::{AsmBuilderMethods, AsmMethods};
|
||||||
|
@ -49,6 +50,7 @@ pub use self::statics::StaticMethods;
|
||||||
pub use self::type_::{
|
pub use self::type_::{
|
||||||
ArgTypeMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods,
|
ArgTypeMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods,
|
||||||
};
|
};
|
||||||
|
pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
|
|
@ -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_incremental;
|
||||||
extern crate rustc_codegen_utils;
|
extern crate rustc_codegen_utils;
|
||||||
extern crate rustc_data_structures;
|
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 libc;
|
||||||
|
extern crate jobserver;
|
||||||
|
extern crate memmap;
|
||||||
|
extern crate num_cpus;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use rustc::dep_graph::WorkProduct;
|
use rustc::dep_graph::WorkProduct;
|
||||||
|
@ -48,7 +57,9 @@ use rustc::middle::lang_items::LangItem;
|
||||||
use rustc::hir::def_id::CrateNum;
|
use rustc::hir::def_id::CrateNum;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
|
use rustc_data_structures::svh::Svh;
|
||||||
use rustc::middle::cstore::{LibSource, CrateSource, NativeLibrary};
|
use rustc::middle::cstore::{LibSource, CrateSource, NativeLibrary};
|
||||||
|
use syntax_pos::symbol::Symbol;
|
||||||
|
|
||||||
// NB: This module needs to be declared first so diagnostics are
|
// NB: This module needs to be declared first so diagnostics are
|
||||||
// registered before they are used.
|
// registered before they are used.
|
||||||
|
@ -63,6 +74,7 @@ pub mod callee;
|
||||||
pub mod glue;
|
pub mod glue;
|
||||||
pub mod meth;
|
pub mod meth;
|
||||||
pub mod mono_item;
|
pub mod mono_item;
|
||||||
|
pub mod back;
|
||||||
|
|
||||||
pub struct ModuleCodegen<M> {
|
pub struct ModuleCodegen<M> {
|
||||||
/// The name of the module. When the crate may be saved between
|
/// 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 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 }
|
__build_diagnostic_array! { librustc_codegen_ssa, DIAGNOSTICS }
|
||||||
|
|
|
@ -13,11 +13,9 @@ test = false
|
||||||
flate2 = "1.0"
|
flate2 = "1.0"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
||||||
serialize = { path = "../libserialize" }
|
|
||||||
syntax = { path = "../libsyntax" }
|
syntax = { path = "../libsyntax" }
|
||||||
syntax_pos = { path = "../libsyntax_pos" }
|
syntax_pos = { path = "../libsyntax_pos" }
|
||||||
rustc = { path = "../librustc" }
|
rustc = { path = "../librustc" }
|
||||||
rustc_allocator = { path = "../librustc_allocator" }
|
|
||||||
rustc_target = { path = "../librustc_target" }
|
rustc_target = { path = "../librustc_target" }
|
||||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||||
rustc_metadata = { path = "../librustc_metadata" }
|
rustc_metadata = { path = "../librustc_metadata" }
|
||||||
|
|
|
@ -31,10 +31,8 @@ extern crate flate2;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
extern crate serialize;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rustc;
|
extern crate rustc;
|
||||||
extern crate rustc_allocator;
|
|
||||||
extern crate rustc_target;
|
extern crate rustc_target;
|
||||||
extern crate rustc_metadata;
|
extern crate rustc_metadata;
|
||||||
extern crate rustc_mir;
|
extern crate rustc_mir;
|
||||||
|
@ -43,16 +41,10 @@ extern crate syntax;
|
||||||
extern crate syntax_pos;
|
extern crate syntax_pos;
|
||||||
#[macro_use] extern crate rustc_data_structures;
|
#[macro_use] extern crate rustc_data_structures;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use rustc::session::Session;
|
|
||||||
use rustc::ty::TyCtxt;
|
use rustc::ty::TyCtxt;
|
||||||
|
|
||||||
pub mod command;
|
|
||||||
pub mod link;
|
pub mod link;
|
||||||
pub mod linker;
|
|
||||||
pub mod codegen_backend;
|
pub mod codegen_backend;
|
||||||
pub mod symbol_export;
|
|
||||||
pub mod symbol_names;
|
pub mod symbol_names;
|
||||||
pub mod symbol_names_test;
|
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 }
|
__build_diagnostic_array! { librustc_codegen_utils, DIAGNOSTICS }
|
||||||
|
|
Loading…
Reference in New Issue