Merge remote-tracking branch 'origin/master' into frewsxcv-san
This commit is contained in:
commit
d482de30ea
1600 changed files with 29527 additions and 21534 deletions
|
@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashSet;
|
|||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||
use rustc_fs_util::fix_windows_verbatim_for_gcc;
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
use rustc_middle::middle::cstore::{EncodedMetadata, LibSource, NativeLib};
|
||||
use rustc_middle::middle::cstore::{EncodedMetadata, LibSource};
|
||||
use rustc_middle::middle::dependency_format::Linkage;
|
||||
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo};
|
||||
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SanitizerSet};
|
||||
|
@ -21,7 +21,10 @@ use super::archive::ArchiveBuilder;
|
|||
use super::command::Command;
|
||||
use super::linker::{self, Linker};
|
||||
use super::rpath::{self, RPathConfig};
|
||||
use crate::{looks_like_rust_object_file, CodegenResults, CrateInfo, METADATA_FILENAME};
|
||||
use crate::{
|
||||
looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib,
|
||||
METADATA_FILENAME,
|
||||
};
|
||||
|
||||
use cc::windows_registry;
|
||||
use tempfile::Builder as TempFileBuilder;
|
||||
|
@ -96,6 +99,9 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
|
|||
path.as_ref(),
|
||||
target_cpu,
|
||||
);
|
||||
if sess.opts.debugging_opts.split_dwarf == config::SplitDwarfKind::Split {
|
||||
link_dwarf_object(sess, &out_filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
if sess.opts.json_artifact_notifications {
|
||||
|
@ -107,22 +113,30 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
|
|||
// Remove the temporary object file and metadata if we aren't saving temps
|
||||
sess.time("link_binary_remove_temps", || {
|
||||
if !sess.opts.cg.save_temps {
|
||||
let remove_temps_from_module = |module: &CompiledModule| {
|
||||
if let Some(ref obj) = module.object {
|
||||
remove(sess, obj);
|
||||
}
|
||||
|
||||
if let Some(ref obj) = module.dwarf_object {
|
||||
remove(sess, obj);
|
||||
}
|
||||
};
|
||||
|
||||
if sess.opts.output_types.should_codegen()
|
||||
&& !preserve_objects_for_their_debuginfo(sess)
|
||||
{
|
||||
for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
|
||||
remove(sess, obj);
|
||||
for module in &codegen_results.modules {
|
||||
remove_temps_from_module(module);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref metadata_module) = codegen_results.metadata_module {
|
||||
if let Some(ref obj) = metadata_module.object {
|
||||
remove(sess, obj);
|
||||
}
|
||||
remove_temps_from_module(metadata_module);
|
||||
}
|
||||
|
||||
if let Some(ref allocator_module) = codegen_results.allocator_module {
|
||||
if let Some(ref obj) = allocator_module.object {
|
||||
remove(sess, obj);
|
||||
}
|
||||
remove_temps_from_module(allocator_module);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -279,12 +293,12 @@ pub fn emit_metadata(sess: &Session, metadata: &EncodedMetadata, tmpdir: &MaybeT
|
|||
out_filename
|
||||
}
|
||||
|
||||
// Create an 'rlib'
|
||||
//
|
||||
// An rlib in its current incarnation is essentially a renamed .a file. The
|
||||
// rlib primarily contains the object file of the crate, but it also contains
|
||||
// all of the object files from native libraries. This is done by unzipping
|
||||
// native libraries and inserting all of the contents into this archive.
|
||||
/// Create an 'rlib'.
|
||||
///
|
||||
/// An rlib in its current incarnation is essentially a renamed .a file. The rlib primarily contains
|
||||
/// the object file of the crate, but it also contains all of the object files from native
|
||||
/// libraries. This is done by unzipping native libraries and inserting all of the contents into
|
||||
/// this archive.
|
||||
fn link_rlib<'a, B: ArchiveBuilder<'a>>(
|
||||
sess: &'a Session,
|
||||
codegen_results: &CodegenResults,
|
||||
|
@ -379,18 +393,17 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
|
|||
ab
|
||||
}
|
||||
|
||||
// Create a static archive
|
||||
//
|
||||
// This is essentially the same thing as an rlib, but it also involves adding
|
||||
// all of the upstream crates' objects into the archive. This will slurp in
|
||||
// all of the native libraries of upstream dependencies as well.
|
||||
//
|
||||
// Additionally, there's no way for us to link dynamic libraries, so we warn
|
||||
// about all dynamic library dependencies that they're not linked in.
|
||||
//
|
||||
// There's no need to include metadata in a static archive, so ensure to not
|
||||
// link in the metadata object file (and also don't prepare the archive with a
|
||||
// metadata file).
|
||||
/// Create a static archive.
|
||||
///
|
||||
/// This is essentially the same thing as an rlib, but it also involves adding all of the upstream
|
||||
/// crates' objects into the archive. This will slurp in all of the native libraries of upstream
|
||||
/// dependencies as well.
|
||||
///
|
||||
/// Additionally, there's no way for us to link dynamic libraries, so we warn about all dynamic
|
||||
/// library dependencies that they're not linked in.
|
||||
///
|
||||
/// There's no need to include metadata in a static archive, so ensure to not link in the metadata
|
||||
/// object file (and also don't prepare the archive with a metadata file).
|
||||
fn link_staticlib<'a, B: ArchiveBuilder<'a>>(
|
||||
sess: &'a Session,
|
||||
codegen_results: &CodegenResults,
|
||||
|
@ -447,10 +460,73 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>(
|
|||
}
|
||||
}
|
||||
|
||||
// Create a dynamic library or executable
|
||||
//
|
||||
// This will invoke the system linker/cc to create the resulting file. This
|
||||
// links to all upstream files as well.
|
||||
fn escape_stdout_stderr_string(s: &[u8]) -> String {
|
||||
str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| {
|
||||
let mut x = "Non-UTF-8 output: ".to_string();
|
||||
x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from));
|
||||
x
|
||||
})
|
||||
}
|
||||
|
||||
const LLVM_DWP_EXECUTABLE: &'static str = "rust-llvm-dwp";
|
||||
|
||||
/// Invoke `llvm-dwp` (shipped alongside rustc) to link `dwo` files from Split DWARF into a `dwp`
|
||||
/// file.
|
||||
fn link_dwarf_object<'a>(sess: &'a Session, executable_out_filename: &Path) {
|
||||
info!("preparing dwp to {}.dwp", executable_out_filename.to_str().unwrap());
|
||||
|
||||
let dwp_out_filename = executable_out_filename.with_extension("dwp");
|
||||
let mut cmd = Command::new(LLVM_DWP_EXECUTABLE);
|
||||
cmd.arg("-e");
|
||||
cmd.arg(executable_out_filename);
|
||||
cmd.arg("-o");
|
||||
cmd.arg(&dwp_out_filename);
|
||||
|
||||
let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(false);
|
||||
if let Some(path) = env::var_os("PATH") {
|
||||
new_path.extend(env::split_paths(&path));
|
||||
}
|
||||
let new_path = env::join_paths(new_path).unwrap();
|
||||
cmd.env("PATH", new_path);
|
||||
|
||||
info!("{:?}", &cmd);
|
||||
match sess.time("run_dwp", || cmd.output()) {
|
||||
Ok(prog) if !prog.status.success() => {
|
||||
sess.struct_err(&format!(
|
||||
"linking dwarf objects with `{}` failed: {}",
|
||||
LLVM_DWP_EXECUTABLE, prog.status
|
||||
))
|
||||
.note(&format!("{:?}", &cmd))
|
||||
.note(&escape_stdout_stderr_string(&prog.stdout))
|
||||
.note(&escape_stdout_stderr_string(&prog.stderr))
|
||||
.emit();
|
||||
info!("linker stderr:\n{}", escape_stdout_stderr_string(&prog.stderr));
|
||||
info!("linker stdout:\n{}", escape_stdout_stderr_string(&prog.stdout));
|
||||
}
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
let dwp_not_found = e.kind() == io::ErrorKind::NotFound;
|
||||
let mut err = if dwp_not_found {
|
||||
sess.struct_err(&format!("linker `{}` not found", LLVM_DWP_EXECUTABLE))
|
||||
} else {
|
||||
sess.struct_err(&format!("could not exec the linker `{}`", LLVM_DWP_EXECUTABLE))
|
||||
};
|
||||
|
||||
err.note(&e.to_string());
|
||||
|
||||
if !dwp_not_found {
|
||||
err.note(&format!("{:?}", &cmd));
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a dynamic library or executable.
|
||||
///
|
||||
/// This will invoke the system linker/cc to create the resulting file. This links to all upstream
|
||||
/// files as well.
|
||||
fn link_natively<'a, B: ArchiveBuilder<'a>>(
|
||||
sess: &'a Session,
|
||||
crate_type: CrateType,
|
||||
|
@ -662,7 +738,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
|
|||
prog.status
|
||||
))
|
||||
.note(&format!("{:?}", &cmd))
|
||||
.note(&escape_string(&output))
|
||||
.note(&escape_stdout_stderr_string(&output))
|
||||
.emit();
|
||||
|
||||
// If MSVC's `link.exe` was expected but the return code
|
||||
|
@ -715,8 +791,8 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
|
|||
|
||||
sess.abort_if_errors();
|
||||
}
|
||||
info!("linker stderr:\n{}", escape_string(&prog.stderr));
|
||||
info!("linker stdout:\n{}", escape_string(&prog.stdout));
|
||||
info!("linker stderr:\n{}", escape_stdout_stderr_string(&prog.stderr));
|
||||
info!("linker stdout:\n{}", escape_stdout_stderr_string(&prog.stdout));
|
||||
}
|
||||
Err(e) => {
|
||||
let linker_not_found = e.kind() == io::ErrorKind::NotFound;
|
||||
|
@ -962,6 +1038,13 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Single mode keeps debuginfo in the same object file, but in such a way that it it skipped
|
||||
// by the linker - so it's expected that when codegen units are linked together that this
|
||||
// debuginfo would be lost without keeping around the temps.
|
||||
if sess.opts.debugging_opts.split_dwarf == config::SplitDwarfKind::Single {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we're on OSX then the equivalent of split dwarf is turned on by
|
||||
// default. The final executable won't actually have any debug information
|
||||
// except it'll have pointers to elsewhere. Historically we've always run
|
||||
|
@ -1677,17 +1760,15 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
|
|||
cmd.take_cmd()
|
||||
}
|
||||
|
||||
// # Native library linking
|
||||
//
|
||||
// User-supplied library search paths (-L on the command line). These are
|
||||
// the same paths used to find Rust crates, so some of them may have been
|
||||
// added already by the previous crate linking code. This only allows them
|
||||
// to be found at compile time so it is still entirely up to outside
|
||||
// forces to make sure that library can be found at runtime.
|
||||
//
|
||||
// Also note that the native libraries linked here are only the ones located
|
||||
// in the current crate. Upstream crates with native library dependencies
|
||||
// may have their native library pulled in above.
|
||||
/// # Native library linking
|
||||
///
|
||||
/// User-supplied library search paths (-L on the command line). These are the same paths used to
|
||||
/// find Rust crates, so some of them may have been added already by the previous crate linking
|
||||
/// code. This only allows them to be found at compile time so it is still entirely up to outside
|
||||
/// forces to make sure that library can be found at runtime.
|
||||
///
|
||||
/// Also note that the native libraries linked here are only the ones located in the current crate.
|
||||
/// Upstream crates with native library dependencies may have their native library pulled in above.
|
||||
fn add_local_native_libraries(
|
||||
cmd: &mut dyn Linker,
|
||||
sess: &Session,
|
||||
|
@ -1727,11 +1808,10 @@ fn add_local_native_libraries(
|
|||
}
|
||||
}
|
||||
|
||||
// # Rust Crate linking
|
||||
//
|
||||
// Rust crates are not considered at all when creating an rlib output. All
|
||||
// dependencies will be linked when producing the final output (instead of
|
||||
// the intermediate rlib version)
|
||||
/// # Rust Crate linking
|
||||
///
|
||||
/// Rust crates are not considered at all when creating an rlib output. All dependencies will be
|
||||
/// linked when producing the final output (instead of the intermediate rlib version).
|
||||
fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
|
||||
cmd: &mut dyn Linker,
|
||||
sess: &'a Session,
|
||||
|
@ -1996,24 +2076,21 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
|
|||
}
|
||||
}
|
||||
|
||||
// Link in all of our upstream crates' native dependencies. Remember that
|
||||
// all of these upstream native dependencies are all non-static
|
||||
// dependencies. We've got two cases then:
|
||||
//
|
||||
// 1. The upstream crate is an rlib. In this case we *must* link in the
|
||||
// native dependency because the rlib is just an archive.
|
||||
//
|
||||
// 2. The upstream crate is a dylib. In order to use the dylib, we have to
|
||||
// have the dependency present on the system somewhere. Thus, we don't
|
||||
// gain a whole lot from not linking in the dynamic dependency to this
|
||||
// crate as well.
|
||||
//
|
||||
// The use case for this is a little subtle. In theory the native
|
||||
// dependencies of a crate are purely an implementation detail of the crate
|
||||
// itself, but the problem arises with generic and inlined functions. If a
|
||||
// generic function calls a native function, then the generic function must
|
||||
// be instantiated in the target crate, meaning that the native symbol must
|
||||
// also be resolved in the target crate.
|
||||
/// Link in all of our upstream crates' native dependencies. Remember that all of these upstream
|
||||
/// native dependencies are all non-static dependencies. We've got two cases then:
|
||||
///
|
||||
/// 1. The upstream crate is an rlib. In this case we *must* link in the native dependency because
|
||||
/// the rlib is just an archive.
|
||||
///
|
||||
/// 2. The upstream crate is a dylib. In order to use the dylib, we have to have the dependency
|
||||
/// present on the system somewhere. Thus, we don't gain a whole lot from not linking in the
|
||||
/// dynamic dependency to this crate as well.
|
||||
///
|
||||
/// The use case for this is a little subtle. In theory the native dependencies of a crate are
|
||||
/// purely an implementation detail of the crate itself, but the problem arises with generic and
|
||||
/// inlined functions. If a generic function calls a native function, then the generic function
|
||||
/// must be instantiated in the target crate, meaning that the native symbol must also be resolved
|
||||
/// in the target crate.
|
||||
fn add_upstream_native_libraries(
|
||||
cmd: &mut dyn Linker,
|
||||
sess: &Session,
|
||||
|
|
|
@ -274,17 +274,20 @@ impl ModuleConfig {
|
|||
}
|
||||
}
|
||||
|
||||
// HACK(eddyb) work around `#[derive]` producing wrong bounds for `Clone`.
|
||||
pub struct TargetMachineFactory<B: WriteBackendMethods>(
|
||||
pub Arc<dyn Fn() -> Result<B::TargetMachine, String> + Send + Sync>,
|
||||
);
|
||||
|
||||
impl<B: WriteBackendMethods> Clone for TargetMachineFactory<B> {
|
||||
fn clone(&self) -> Self {
|
||||
TargetMachineFactory(self.0.clone())
|
||||
}
|
||||
/// Configuration passed to the function returned by the `target_machine_factory`.
|
||||
pub struct TargetMachineFactoryConfig {
|
||||
/// Split DWARF is enabled in LLVM by checking that `TM.MCOptions.SplitDwarfFile` isn't empty,
|
||||
/// so the path to the dwarf object has to be provided when we create the target machine.
|
||||
/// This can be ignored by backends which do not need it for their Split DWARF support.
|
||||
pub split_dwarf_file: Option<PathBuf>,
|
||||
}
|
||||
|
||||
pub type TargetMachineFactoryFn<B> = Arc<
|
||||
dyn Fn(TargetMachineFactoryConfig) -> Result<<B as WriteBackendMethods>::TargetMachine, String>
|
||||
+ Send
|
||||
+ Sync,
|
||||
>;
|
||||
|
||||
pub type ExportedSymbols = FxHashMap<CrateNum, Arc<Vec<(String, SymbolExportLevel)>>>;
|
||||
|
||||
/// Additional resources used by optimize_and_codegen (not module specific)
|
||||
|
@ -305,12 +308,13 @@ pub struct CodegenContext<B: WriteBackendMethods> {
|
|||
pub regular_module_config: Arc<ModuleConfig>,
|
||||
pub metadata_module_config: Arc<ModuleConfig>,
|
||||
pub allocator_module_config: Arc<ModuleConfig>,
|
||||
pub tm_factory: TargetMachineFactory<B>,
|
||||
pub tm_factory: TargetMachineFactoryFn<B>,
|
||||
pub msvc_imps_needed: bool,
|
||||
pub is_pe_coff: bool,
|
||||
pub target_pointer_width: u32,
|
||||
pub target_arch: String,
|
||||
pub debuginfo: config::DebugInfo,
|
||||
pub split_dwarf_kind: config::SplitDwarfKind,
|
||||
|
||||
// Number of cgus excluding the allocator/metadata modules
|
||||
pub total_cgus: usize,
|
||||
|
@ -627,6 +631,12 @@ fn produce_final_output_artifacts(
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(ref path) = module.dwarf_object {
|
||||
if !keep_numbered_objects {
|
||||
remove(sess, path);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref path) = module.bytecode {
|
||||
if !keep_numbered_bitcode {
|
||||
remove(sess, path);
|
||||
|
@ -849,6 +859,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
|
|||
name: module.name,
|
||||
kind: ModuleKind::Regular,
|
||||
object,
|
||||
dwarf_object: None,
|
||||
bytecode: None,
|
||||
}))
|
||||
}
|
||||
|
@ -1020,13 +1031,14 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
regular_module_config: regular_config,
|
||||
metadata_module_config: metadata_config,
|
||||
allocator_module_config: allocator_config,
|
||||
tm_factory: TargetMachineFactory(backend.target_machine_factory(tcx.sess, ol)),
|
||||
tm_factory: backend.target_machine_factory(tcx.sess, ol),
|
||||
total_cgus,
|
||||
msvc_imps_needed: msvc_imps_needed(tcx),
|
||||
is_pe_coff: tcx.sess.target.is_like_windows,
|
||||
target_pointer_width: tcx.sess.target.pointer_width,
|
||||
target_arch: tcx.sess.target.arch.clone(),
|
||||
debuginfo: tcx.sess.opts.debuginfo,
|
||||
split_dwarf_kind: tcx.sess.opts.debugging_opts.split_dwarf,
|
||||
};
|
||||
|
||||
// This is the "main loop" of parallel work happening for parallel codegen.
|
||||
|
|
|
@ -1,18 +1,3 @@
|
|||
//! Codegen the completed AST to the LLVM IR.
|
||||
//!
|
||||
//! Some functions here, such as `codegen_block` and `codegen_expr`, return a value --
|
||||
//! the result of the codegen to LLVM -- while others, such as `codegen_fn`
|
||||
//! and `mono_item`, are called only for the side effect of adding a
|
||||
//! particular definition to the LLVM IR output we're producing.
|
||||
//!
|
||||
//! Hopefully useful general knowledge about codegen:
|
||||
//!
|
||||
//! * There's no way to find out the `Ty` type of a `Value`. Doing so
|
||||
//! would be "trying to get the eggs out of an omelette" (credit:
|
||||
//! pcwalton). You can, instead, find out its `llvm::Type` by calling `val_ty`,
|
||||
//! but one `llvm::Type` corresponds to many `Ty`s; for instance, `tup(int, int,
|
||||
//! int)` and `rec(x=int, y=int, z=int)` will have the same `llvm::Type`.
|
||||
|
||||
use crate::back::write::{
|
||||
compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm,
|
||||
submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen,
|
||||
|
@ -46,7 +31,6 @@ use rustc_session::cgu_reuse_tracker::CguReuse;
|
|||
use rustc_session::config::{self, EntryFnType};
|
||||
use rustc_session::utils::NativeLibKind;
|
||||
use rustc_session::Session;
|
||||
use rustc_symbol_mangling::test as symbol_names_test;
|
||||
use rustc_target::abi::{Align, LayoutOf, VariantIdx};
|
||||
|
||||
use std::cmp;
|
||||
|
@ -486,8 +470,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
|
||||
ongoing_codegen.codegen_finished(tcx);
|
||||
|
||||
finalize_tcx(tcx);
|
||||
|
||||
ongoing_codegen.check_for_errors(tcx.sess);
|
||||
|
||||
return ongoing_codegen;
|
||||
|
@ -688,14 +670,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
total_codegen_time.into_inner(),
|
||||
);
|
||||
|
||||
rustc_incremental::assert_module_sources::assert_module_sources(tcx);
|
||||
|
||||
symbol_names_test::report_symbol_names(tcx);
|
||||
|
||||
ongoing_codegen.check_for_errors(tcx.sess);
|
||||
|
||||
finalize_tcx(tcx);
|
||||
|
||||
ongoing_codegen.into_inner()
|
||||
}
|
||||
|
||||
|
@ -746,18 +722,6 @@ impl<B: ExtraBackendMethods> Drop for AbortCodegenOnDrop<B> {
|
|||
}
|
||||
}
|
||||
|
||||
fn finalize_tcx(tcx: TyCtxt<'_>) {
|
||||
tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx));
|
||||
tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx));
|
||||
|
||||
// We assume that no queries are run past here. If there are new queries
|
||||
// after this point, they'll show up as "<unknown>" in self-profiling data.
|
||||
{
|
||||
let _prof_timer = tcx.prof.generic_activity("self_profile_alloc_query_strings");
|
||||
tcx.alloc_self_profile_query_strings();
|
||||
}
|
||||
}
|
||||
|
||||
impl CrateInfo {
|
||||
pub fn new(tcx: TyCtxt<'_>) -> CrateInfo {
|
||||
let mut info = CrateInfo {
|
||||
|
@ -766,7 +730,7 @@ impl CrateInfo {
|
|||
profiler_runtime: None,
|
||||
is_no_builtins: Default::default(),
|
||||
native_libraries: Default::default(),
|
||||
used_libraries: tcx.native_libraries(LOCAL_CRATE),
|
||||
used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(),
|
||||
link_args: tcx.link_args(LOCAL_CRATE),
|
||||
crate_name: Default::default(),
|
||||
used_crates_dynamic: cstore::used_crates(tcx, LinkagePreference::RequireDynamic),
|
||||
|
@ -787,7 +751,8 @@ impl CrateInfo {
|
|||
info.missing_lang_items.reserve(n_crates);
|
||||
|
||||
for &cnum in crates.iter() {
|
||||
info.native_libraries.insert(cnum, tcx.native_libraries(cnum));
|
||||
info.native_libraries
|
||||
.insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect());
|
||||
info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string());
|
||||
info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum));
|
||||
if tcx.is_panic_runtime(cnum) {
|
||||
|
|
|
@ -21,15 +21,17 @@ extern crate tracing;
|
|||
#[macro_use]
|
||||
extern crate rustc_middle;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_middle::dep_graph::WorkProduct;
|
||||
use rustc_middle::middle::cstore::{CrateSource, LibSource, NativeLib};
|
||||
use rustc_middle::middle::cstore::{self, CrateSource, LibSource};
|
||||
use rustc_middle::middle::dependency_format::Dependencies;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_session::config::{OutputFilenames, OutputType, RUST_CGU_EXT};
|
||||
use rustc_session::utils::NativeLibKind;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
|
@ -64,13 +66,15 @@ impl<M> ModuleCodegen<M> {
|
|||
pub fn into_compiled_module(
|
||||
self,
|
||||
emit_obj: bool,
|
||||
emit_dwarf_obj: bool,
|
||||
emit_bc: bool,
|
||||
outputs: &OutputFilenames,
|
||||
) -> CompiledModule {
|
||||
let object = emit_obj.then(|| outputs.temp_path(OutputType::Object, Some(&self.name)));
|
||||
let dwarf_object = emit_dwarf_obj.then(|| outputs.temp_path_dwo(Some(&self.name)));
|
||||
let bytecode = emit_bc.then(|| outputs.temp_path(OutputType::Bitcode, Some(&self.name)));
|
||||
|
||||
CompiledModule { name: self.name.clone(), kind: self.kind, object, bytecode }
|
||||
CompiledModule { name: self.name.clone(), kind: self.kind, object, dwarf_object, bytecode }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,6 +83,7 @@ pub struct CompiledModule {
|
|||
pub name: String,
|
||||
pub kind: ModuleKind,
|
||||
pub object: Option<PathBuf>,
|
||||
pub dwarf_object: Option<PathBuf>,
|
||||
pub bytecode: Option<PathBuf>,
|
||||
}
|
||||
|
||||
|
@ -102,6 +107,19 @@ bitflags::bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Encodable, Decodable, HashStable)]
|
||||
pub struct NativeLib {
|
||||
pub kind: NativeLibKind,
|
||||
pub name: Option<Symbol>,
|
||||
pub cfg: Option<ast::MetaItem>,
|
||||
}
|
||||
|
||||
impl From<&cstore::NativeLib> for NativeLib {
|
||||
fn from(lib: &cstore::NativeLib) -> Self {
|
||||
NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Misc info we load from metadata to persist beyond the tcx.
|
||||
///
|
||||
/// Note: though `CrateNum` is only meaningful within the same tcx, information within `CrateInfo`
|
||||
|
@ -116,9 +134,9 @@ pub struct CrateInfo {
|
|||
pub compiler_builtins: Option<CrateNum>,
|
||||
pub profiler_runtime: Option<CrateNum>,
|
||||
pub is_no_builtins: FxHashSet<CrateNum>,
|
||||
pub native_libraries: FxHashMap<CrateNum, Lrc<Vec<NativeLib>>>,
|
||||
pub native_libraries: FxHashMap<CrateNum, Vec<NativeLib>>,
|
||||
pub crate_name: FxHashMap<CrateNum, String>,
|
||||
pub used_libraries: Lrc<Vec<NativeLib>>,
|
||||
pub used_libraries: Vec<NativeLib>,
|
||||
pub link_args: Lrc<Vec<String>>,
|
||||
pub used_crate_source: FxHashMap<CrateNum, Lrc<CrateSource>>,
|
||||
pub used_crates_static: Vec<(CrateNum, LibSource)>,
|
||||
|
|
|
@ -112,12 +112,12 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
|
|||
};
|
||||
|
||||
// Allow uses of projections that are ZSTs or from scalar fields.
|
||||
let is_consume = match context {
|
||||
let is_consume = matches!(
|
||||
context,
|
||||
PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::Copy | NonMutatingUseContext::Move,
|
||||
) => true,
|
||||
_ => false,
|
||||
};
|
||||
)
|
||||
);
|
||||
if is_consume {
|
||||
let base_ty =
|
||||
mir::Place::ty_from(place_ref.local, proj_base, self.fx.mir, cx.tcx());
|
||||
|
|
|
@ -522,7 +522,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
mut bx: Bx,
|
||||
terminator: &mir::Terminator<'tcx>,
|
||||
func: &mir::Operand<'tcx>,
|
||||
args: &Vec<mir::Operand<'tcx>>,
|
||||
args: &[mir::Operand<'tcx>],
|
||||
destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>,
|
||||
cleanup: Option<mir::BasicBlock>,
|
||||
fn_span: Span,
|
||||
|
@ -1395,6 +1395,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
dst: PlaceRef<'tcx, Bx::Value>,
|
||||
) {
|
||||
let src = self.codegen_operand(bx, src);
|
||||
|
||||
// Special-case transmutes between scalars as simple bitcasts.
|
||||
match (&src.layout.abi, &dst.layout.abi) {
|
||||
(abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
|
||||
// HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
|
||||
if (src_scalar.value == abi::Pointer) == (dst_scalar.value == abi::Pointer) {
|
||||
assert_eq!(src.layout.size, dst.layout.size);
|
||||
|
||||
// NOTE(eddyb) the `from_immediate` and `to_immediate_scalar`
|
||||
// conversions allow handling `bool`s the same as `u8`s.
|
||||
let src = bx.from_immediate(src.immediate());
|
||||
let src_as_dst = bx.bitcast(src, bx.backend_type(dst.layout));
|
||||
Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let llty = bx.backend_type(src.layout);
|
||||
let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty));
|
||||
let align = src.layout.align.abi.min(dst.align);
|
||||
|
|
|
@ -11,7 +11,7 @@ use super::FunctionCx;
|
|||
|
||||
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
pub fn eval_mir_constant_to_operand(
|
||||
&mut self,
|
||||
&self,
|
||||
bx: &mut Bx,
|
||||
constant: &mir::Constant<'tcx>,
|
||||
) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> {
|
||||
|
@ -21,7 +21,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
|
||||
pub fn eval_mir_constant(
|
||||
&mut self,
|
||||
&self,
|
||||
constant: &mir::Constant<'tcx>,
|
||||
) -> Result<ConstValue<'tcx>, ErrorHandled> {
|
||||
match self.monomorphize(constant.literal).val {
|
||||
|
|
|
@ -8,7 +8,7 @@ use rustc_span::symbol::{kw, Symbol};
|
|||
use rustc_span::{BytePos, Span};
|
||||
use rustc_target::abi::{LayoutOf, Size};
|
||||
|
||||
use super::operand::OperandValue;
|
||||
use super::operand::{OperandRef, OperandValue};
|
||||
use super::place::PlaceRef;
|
||||
use super::{FunctionCx, LocalRef};
|
||||
|
||||
|
@ -116,6 +116,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
span
|
||||
}
|
||||
|
||||
fn spill_operand_to_stack(
|
||||
operand: &OperandRef<'tcx, Bx::Value>,
|
||||
name: Option<String>,
|
||||
bx: &mut Bx,
|
||||
) -> PlaceRef<'tcx, Bx::Value> {
|
||||
// "Spill" the value onto the stack, for debuginfo,
|
||||
// without forcing non-debuginfo uses of the local
|
||||
// to also load from the stack every single time.
|
||||
// FIXME(#68817) use `llvm.dbg.value` instead,
|
||||
// at least for the cases which LLVM handles correctly.
|
||||
let spill_slot = PlaceRef::alloca(bx, operand.layout);
|
||||
if let Some(name) = name {
|
||||
bx.set_var_name(spill_slot.llval, &(name + ".dbg.spill"));
|
||||
}
|
||||
operand.val.store(bx, spill_slot);
|
||||
spill_slot
|
||||
}
|
||||
|
||||
/// Apply debuginfo and/or name, after creating the `alloca` for a local,
|
||||
/// or initializing the local with an operand (whichever applies).
|
||||
pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
|
||||
|
@ -152,7 +170,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
// (after #67586 gets fixed).
|
||||
None
|
||||
} else {
|
||||
let name = kw::Invalid;
|
||||
let name = kw::Empty;
|
||||
let decl = &self.mir.local_decls[local];
|
||||
let dbg_var = if full_debug_info {
|
||||
self.adjusted_span_and_dbg_scope(decl.source_info).map(
|
||||
|
@ -186,7 +204,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
None
|
||||
} else {
|
||||
Some(match whole_local_var.or(fallback_var) {
|
||||
Some(var) if var.name != kw::Invalid => var.name.to_string(),
|
||||
Some(var) if var.name != kw::Empty => var.name.to_string(),
|
||||
_ => format!("{:?}", local),
|
||||
})
|
||||
};
|
||||
|
@ -226,17 +244,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
return;
|
||||
}
|
||||
|
||||
// "Spill" the value onto the stack, for debuginfo,
|
||||
// without forcing non-debuginfo uses of the local
|
||||
// to also load from the stack every single time.
|
||||
// FIXME(#68817) use `llvm.dbg.value` instead,
|
||||
// at least for the cases which LLVM handles correctly.
|
||||
let spill_slot = PlaceRef::alloca(bx, operand.layout);
|
||||
if let Some(name) = name {
|
||||
bx.set_var_name(spill_slot.llval, &(name + ".dbg.spill"));
|
||||
}
|
||||
operand.val.store(bx, spill_slot);
|
||||
spill_slot
|
||||
Self::spill_operand_to_stack(operand, name, bx)
|
||||
}
|
||||
|
||||
LocalRef::Place(place) => *place,
|
||||
|
@ -308,6 +316,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
/// Partition all `VarDebugInfo` in `self.mir`, by their base `Local`.
|
||||
pub fn compute_per_local_var_debug_info(
|
||||
&self,
|
||||
bx: &mut Bx,
|
||||
) -> Option<IndexVec<mir::Local, Vec<PerLocalVarDebugInfo<'tcx, Bx::DIVariable>>>> {
|
||||
let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full;
|
||||
|
||||
|
@ -322,31 +331,63 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
} else {
|
||||
None
|
||||
};
|
||||
let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| {
|
||||
let place = var.place;
|
||||
let var_ty = self.monomorphized_place_ty(place.as_ref());
|
||||
let var_kind = if self.mir.local_kind(place.local) == mir::LocalKind::Arg
|
||||
&& place.projection.is_empty()
|
||||
&& var.source_info.scope == mir::OUTERMOST_SOURCE_SCOPE
|
||||
{
|
||||
let arg_index = place.local.index() - 1;
|
||||
|
||||
// FIXME(eddyb) shouldn't `ArgumentVariable` indices be
|
||||
// offset in closures to account for the hidden environment?
|
||||
// Also, is this `+ 1` needed at all?
|
||||
VariableKind::ArgumentVariable(arg_index + 1)
|
||||
} else {
|
||||
VariableKind::LocalVariable
|
||||
let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| {
|
||||
let (var_ty, var_kind) = match var.value {
|
||||
mir::VarDebugInfoContents::Place(place) => {
|
||||
let var_ty = self.monomorphized_place_ty(place.as_ref());
|
||||
let var_kind = if self.mir.local_kind(place.local) == mir::LocalKind::Arg
|
||||
&& place.projection.is_empty()
|
||||
&& var.source_info.scope == mir::OUTERMOST_SOURCE_SCOPE
|
||||
{
|
||||
let arg_index = place.local.index() - 1;
|
||||
|
||||
// FIXME(eddyb) shouldn't `ArgumentVariable` indices be
|
||||
// offset in closures to account for the hidden environment?
|
||||
// Also, is this `+ 1` needed at all?
|
||||
VariableKind::ArgumentVariable(arg_index + 1)
|
||||
} else {
|
||||
VariableKind::LocalVariable
|
||||
};
|
||||
(var_ty, var_kind)
|
||||
}
|
||||
mir::VarDebugInfoContents::Const(c) => {
|
||||
let ty = self.monomorphize(c.literal.ty);
|
||||
(ty, VariableKind::LocalVariable)
|
||||
}
|
||||
};
|
||||
|
||||
self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
|
||||
});
|
||||
|
||||
per_local[var.place.local].push(PerLocalVarDebugInfo {
|
||||
name: var.name,
|
||||
source_info: var.source_info,
|
||||
dbg_var,
|
||||
projection: var.place.projection,
|
||||
});
|
||||
match var.value {
|
||||
mir::VarDebugInfoContents::Place(place) => {
|
||||
per_local[place.local].push(PerLocalVarDebugInfo {
|
||||
name: var.name,
|
||||
source_info: var.source_info,
|
||||
dbg_var,
|
||||
projection: place.projection,
|
||||
});
|
||||
}
|
||||
mir::VarDebugInfoContents::Const(c) => {
|
||||
if let Some(dbg_var) = dbg_var {
|
||||
let dbg_loc = match self.dbg_loc(var.source_info) {
|
||||
Some(dbg_loc) => dbg_loc,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) {
|
||||
let base = Self::spill_operand_to_stack(
|
||||
&operand,
|
||||
Some(var.name.to_string()),
|
||||
bx,
|
||||
);
|
||||
|
||||
bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(per_local)
|
||||
}
|
||||
|
|
|
@ -83,9 +83,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
return;
|
||||
}
|
||||
|
||||
sym::unreachable => {
|
||||
return;
|
||||
}
|
||||
sym::va_start => bx.va_start(args[0].immediate()),
|
||||
sym::va_end => bx.va_end(args[0].immediate()),
|
||||
sym::size_of_val => {
|
||||
|
@ -106,8 +103,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
bx.const_usize(bx.layout_of(tp_ty).align.abi.bytes())
|
||||
}
|
||||
}
|
||||
sym::size_of
|
||||
| sym::pref_align_of
|
||||
sym::pref_align_of
|
||||
| sym::min_align_of
|
||||
| sym::needs_drop
|
||||
| sym::type_id
|
||||
|
@ -119,10 +115,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
.unwrap();
|
||||
OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx)
|
||||
}
|
||||
// Effectively no-op
|
||||
sym::forget => {
|
||||
return;
|
||||
}
|
||||
sym::offset => {
|
||||
let ptr = args[0].immediate();
|
||||
let offset = args[1].immediate();
|
||||
|
@ -218,9 +210,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
sym::add_with_overflow
|
||||
| sym::sub_with_overflow
|
||||
| sym::mul_with_overflow
|
||||
| sym::wrapping_add
|
||||
| sym::wrapping_sub
|
||||
| sym::wrapping_mul
|
||||
| sym::unchecked_div
|
||||
| sym::unchecked_rem
|
||||
| sym::unchecked_shl
|
||||
|
@ -254,9 +243,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
|
||||
return;
|
||||
}
|
||||
sym::wrapping_add => bx.add(args[0].immediate(), args[1].immediate()),
|
||||
sym::wrapping_sub => bx.sub(args[0].immediate(), args[1].immediate()),
|
||||
sym::wrapping_mul => bx.mul(args[0].immediate(), args[1].immediate()),
|
||||
sym::exact_div => {
|
||||
if signed {
|
||||
bx.exactsdiv(args[0].immediate(), args[1].immediate())
|
||||
|
@ -538,8 +524,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
};
|
||||
|
||||
let ty = substs.type_at(0);
|
||||
if int_type_width_signed(ty, bx.tcx()).is_some() {
|
||||
bx.atomic_rmw(atom_op, args[0].immediate(), args[1].immediate(), order)
|
||||
if int_type_width_signed(ty, bx.tcx()).is_some()
|
||||
|| (ty.is_unsafe_ptr() && op == "xchg")
|
||||
{
|
||||
let mut ptr = args[0].immediate();
|
||||
let mut val = args[1].immediate();
|
||||
if ty.is_unsafe_ptr() {
|
||||
// Some platforms do not support atomic operations on pointers,
|
||||
// so we cast to integer first.
|
||||
let ptr_llty = bx.type_ptr_to(bx.type_isize());
|
||||
ptr = bx.pointercast(ptr, ptr_llty);
|
||||
val = bx.ptrtoint(val, bx.type_isize());
|
||||
}
|
||||
bx.atomic_rmw(atom_op, ptr, val, order)
|
||||
} else {
|
||||
return invalid_monomorphization(ty);
|
||||
}
|
||||
|
|
|
@ -186,7 +186,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
caller_location: None,
|
||||
};
|
||||
|
||||
fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info();
|
||||
fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut bx);
|
||||
|
||||
for const_ in &mir.required_consts {
|
||||
if let Err(err) = fx.eval_mir_constant(const_) {
|
||||
|
|
|
@ -489,6 +489,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
|
||||
mir::Rvalue::Discriminant(ref place) => {
|
||||
let discr_ty = rvalue.ty(self.mir, bx.tcx());
|
||||
let discr_ty = self.monomorphize(discr_ty);
|
||||
let discr = self
|
||||
.codegen_place(&mut bx, place.as_ref())
|
||||
.codegen_get_discr(&mut bx, discr_ty);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use super::write::WriteBackendMethods;
|
||||
use super::CodegenObject;
|
||||
use crate::back::write::TargetMachineFactoryFn;
|
||||
use crate::{CodegenResults, ModuleCodegen};
|
||||
|
||||
use rustc_ast::expand::allocator::AllocatorKind;
|
||||
|
@ -21,7 +22,6 @@ use rustc_target::spec::Target;
|
|||
pub use rustc_data_structures::sync::MetadataRef;
|
||||
|
||||
use std::any::Any;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait BackendTypes {
|
||||
type Value: CodegenObject;
|
||||
|
@ -123,7 +123,7 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se
|
|||
&self,
|
||||
sess: &Session,
|
||||
opt_level: config::OptLevel,
|
||||
) -> Arc<dyn Fn() -> Result<Self::TargetMachine, String> + Send + Sync>;
|
||||
) -> TargetMachineFactoryFn<Self>;
|
||||
fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str;
|
||||
fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str>;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue