| // tidy-alphabetical-start | |
| #![feature(deref_patterns)] | |
| #![feature(file_buffered)] | |
| #![feature(negative_impls)] | |
| #![feature(option_into_flat_iter)] | |
| #![feature(trait_alias)] | |
| #![feature(try_blocks)] | |
| #![recursion_limit = "256"] | |
| // tidy-alphabetical-end | |
| //! This crate contains codegen code that is used by all codegen backends (LLVM and others). | |
| //! The backend-agnostic functions of this crate use functions defined in various traits that | |
| //! have to be implemented by each backend. | |
| use std::collections::BTreeSet; | |
| use std::io; | |
| use std::path::{Path, PathBuf}; | |
| use std::sync::Arc; | |
| use rustc_abi::Size; | |
| use rustc_crate_store::{self as cstore, CrateSource}; | |
| use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; | |
| use rustc_data_structures::unord::{UnordMap, UnordSet}; | |
| use rustc_hir::CRATE_HIR_ID; | |
| use rustc_hir::attrs::{CfgEntry, WindowsSubsystemKind}; | |
| use rustc_hir::def_id::CrateNum; | |
| use rustc_lint_defs::builtin::{LINKER_INFO, LINKER_MESSAGES}; | |
| use rustc_macros::{Decodable, Encodable}; | |
| use rustc_metadata::EncodedMetadata; | |
| use rustc_middle::dep_graph::WorkProduct; | |
| use rustc_middle::lint::StableLevelSpec; | |
| use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; | |
| use rustc_middle::middle::dependency_format::Dependencies; | |
| use rustc_middle::middle::exported_symbols::SymbolExportKind; | |
| use rustc_middle::ty::TyCtxt; | |
| use rustc_middle::util::Providers; | |
| use rustc_serialize::opaque::{FileEncoder, MemDecoder}; | |
| use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; | |
| use rustc_session::Session; | |
| use rustc_session::config::{OutputFilenames, OutputType}; | |
| use rustc_span::{Span, Symbol}; | |
| use rustc_structures::{CrateType, NativeLibKind}; | |
| pub mod assert_module_sources; | |
| pub mod back; | |
| pub mod base; | |
| pub mod codegen_attrs; | |
| pub mod common; | |
| pub mod debuginfo; | |
| pub mod diagnostics; | |
| pub mod meth; | |
| pub mod mir; | |
| pub mod mono_item; | |
| pub mod size_of_val; | |
| pub mod target_features; | |
| pub mod traits; | |
| pub struct ModuleCodegen<M> { | |
| /// The name of the module. When the crate may be saved between | |
| /// compilations, incremental compilation requires that name be | |
| /// unique amongst **all** crates. Therefore, it should contain | |
| /// something unique to this crate (e.g., a module path) as well | |
| /// as the crate name and disambiguator. | |
| /// We currently generate these names via CodegenUnit::build_cgu_name(). | |
| pub name: String, | |
| pub module_llvm: M, | |
| pub kind: ModuleKind, | |
| /// Saving the ThinLTO buffer for embedding in the object file. | |
| pub thin_lto_buffer: Option<Vec<u8>>, | |
| } | |
| impl<M> ModuleCodegen<M> { | |
| pub fn new_regular(name: impl Into<String>, module: M) -> Self { | |
| Self { | |
| name: name.into(), | |
| module_llvm: module, | |
| kind: ModuleKind::Regular, | |
| thin_lto_buffer: None, | |
| } | |
| } | |
| pub fn new_allocator(name: impl Into<String>, module: M) -> Self { | |
| Self { | |
| name: name.into(), | |
| module_llvm: module, | |
| kind: ModuleKind::Allocator, | |
| thin_lto_buffer: None, | |
| } | |
| } | |
| pub fn into_compiled_module( | |
| self, | |
| emit_obj: bool, | |
| emit_dwarf_obj: bool, | |
| emit_bc: bool, | |
| emit_asm: bool, | |
| emit_ir: bool, | |
| outputs: &OutputFilenames, | |
| ) -> CompiledModule { | |
| let object = emit_obj.then(|| outputs.temp_path_for_cgu(OutputType::Object, &self.name)); | |
| let dwarf_object = emit_dwarf_obj.then(|| outputs.temp_path_dwo_for_cgu(&self.name)); | |
| let bytecode = emit_bc.then(|| outputs.temp_path_for_cgu(OutputType::Bitcode, &self.name)); | |
| let assembly = | |
| emit_asm.then(|| outputs.temp_path_for_cgu(OutputType::Assembly, &self.name)); | |
| let llvm_ir = | |
| emit_ir.then(|| outputs.temp_path_for_cgu(OutputType::LlvmAssembly, &self.name)); | |
| CompiledModule { | |
| name: self.name, | |
| kind: self.kind, | |
| object, | |
| global_asm_object: None, | |
| dwarf_object, | |
| bytecode, | |
| assembly, | |
| llvm_ir, | |
| links_from_incr_cache: Vec::new(), | |
| } | |
| } | |
| } | |
| #[derive(Debug, Encodable, Decodable)] | |
| pub struct CompiledModule { | |
| pub name: String, | |
| pub kind: ModuleKind, | |
| pub object: Option<PathBuf>, | |
| pub global_asm_object: Option<PathBuf>, | |
| pub dwarf_object: Option<PathBuf>, | |
| pub bytecode: Option<PathBuf>, | |
| pub assembly: Option<PathBuf>, // --emit=asm | |
| pub llvm_ir: Option<PathBuf>, // --emit=llvm-ir, llvm-bc is in bytecode | |
| pub links_from_incr_cache: Vec<PathBuf>, | |
| } | |
| impl CompiledModule { | |
| /// Call `emit` function with every artifact type currently compiled | |
| pub fn for_each_output(&self, mut emit: impl FnMut(&Path, OutputType)) { | |
| if let Some(path) = self.object.as_deref() { | |
| emit(path, OutputType::Object); | |
| } | |
| if let Some(path) = self.bytecode.as_deref() { | |
| emit(path, OutputType::Bitcode); | |
| } | |
| if let Some(path) = self.llvm_ir.as_deref() { | |
| emit(path, OutputType::LlvmAssembly); | |
| } | |
| if let Some(path) = self.assembly.as_deref() { | |
| emit(path, OutputType::Assembly); | |
| } | |
| } | |
| } | |
| pub(crate) struct CachedModuleCodegen { | |
| pub name: String, | |
| pub source: WorkProduct, | |
| } | |
| #[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable)] | |
| pub enum ModuleKind { | |
| Regular, | |
| Allocator, | |
| } | |
| bitflags::bitflags! { | |
| /// This previously had an `UNALIGNED` variant, but that should never be done via flags. | |
| /// If you want something to be unaligned, see [`mir::place::PlaceRef::unaligned`]. | |
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] | |
| pub struct MemFlags: u8 { | |
| const VOLATILE = 1 << 0; | |
| const NONTEMPORAL = 1 << 1; | |
| /// Indicates that writing through the stored pointer is undefined behavior. | |
| /// Only valid on stores of pointers, or pairs where the first element is a pointer. | |
| /// In the latter case, the flag only applies to the first element of the pair. | |
| const CAPTURES_READ_ONLY = 1 << 3; | |
| } | |
| } | |
| #[derive(Debug, Copy, Clone)] | |
| pub struct RetagInfo<V> { | |
| /// The size of the initial range within the allocation that is | |
| /// associated with the permission created by the retag. | |
| pub size: Size, | |
| /// Encoded type information used to determine the kind of permission | |
| /// created by the retag. | |
| pub flags: RetagFlags, | |
| /// A pointer to a constant array of (offset, size) pairs describing | |
| /// the ranges covered by `UnsafeCell` within the pointee type. | |
| pub im_layout: V, | |
| /// A pointer to a constant array of (offset, size) pairs describing | |
| /// the ranges covered by `UnsafePinned` within the pointee type. | |
| pub pin_layout: V, | |
| } | |
| bitflags::bitflags! { | |
| #[repr(C)] | |
| #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | |
| pub struct RetagFlags: u8 { | |
| /// If this is a function-entry retag. | |
| const IS_PROTECTED = 1 << 0; | |
| /// If this is a mutable reference or a `Box`. | |
| const IS_MUTABLE = 1 << 1; | |
| /// If this is a `Box`. | |
| const IS_BOX = 1 << 2; | |
| /// If the pointee type is `Freeze` | |
| const IS_FREEZE = 1 << 3; | |
| } | |
| } | |
| // This is the same as `rustc_crate_store::NativeLib`, except: | |
| // - (important) the `foreign_module` field is missing, because it contains a `DefId`, which can't | |
| // be encoded with `FileEncoder`. | |
| // - (less important) the `verbatim` field is a `bool` rather than an `Option<bool>`, because here | |
| // we can treat `false` and `absent` the same. | |
| #[derive(Clone, Debug, Encodable, Decodable)] | |
| pub struct NativeLib { | |
| pub kind: NativeLibKind, | |
| pub name: Symbol, | |
| pub cfg: Option<CfgEntry>, | |
| pub verbatim: bool, | |
| pub dll_imports: Vec<cstore::DllImport>, | |
| } | |
| impl From<&cstore::NativeLib> for NativeLib { | |
| fn from(lib: &cstore::NativeLib) -> Self { | |
| NativeLib { | |
| kind: lib.kind, | |
| name: lib.name, | |
| cfg: lib.cfg.clone(), | |
| verbatim: lib.verbatim.unwrap_or(false), | |
| dll_imports: lib.dll_imports.clone(), | |
| } | |
| } | |
| } | |
| /// A symbol to make visible from a linked artifact. | |
| #[derive(Clone, Debug, Encodable, Decodable)] | |
| pub struct SymbolExport { | |
| /// Name to make visible from the linked artifact. | |
| pub name: String, | |
| /// Kind of symbol, used for target-specific export directives and name decoration. | |
| pub kind: SymbolExportKind, | |
| /// Name of the symbol as seen by the linker, when it differs from `name`. | |
| pub link_name: Option<String>, | |
| } | |
| impl SymbolExport { | |
| pub fn new(name: String, kind: SymbolExportKind) -> SymbolExport { | |
| SymbolExport { name, kind, link_name: None } | |
| } | |
| pub fn with_link_name(name: String, kind: SymbolExportKind, link_name: String) -> SymbolExport { | |
| let link_name = if link_name == name { None } else { Some(link_name) }; | |
| SymbolExport { name, kind, link_name } | |
| } | |
| } | |
| #[derive(Clone, Debug, Encodable, Decodable)] | |
| pub struct EiiLinkageImplInfo { | |
| pub span: Span, | |
| pub impl_crate: CrateNum, | |
| } | |
| #[derive(Clone, Debug, Encodable, Decodable)] | |
| pub struct EiiLinkageInfo { | |
| pub name: Symbol, | |
| pub impls: Vec<EiiLinkageImplInfo>, | |
| pub default_impl: Option<EiiLinkageImplInfo>, | |
| } | |
| /// Misc info we load from metadata to persist beyond the tcx. | |
| /// | |
| /// Note: though `CrateNum` is only meaningful within the same tcx, information within `CrateInfo` | |
| /// is self-contained. `CrateNum` can be viewed as a unique identifier within a `CrateInfo`, where | |
| /// `used_crate_source` contains all `CrateSource` of the dependents, and maintains a mapping from | |
| /// identifiers (`CrateNum`) to `CrateSource`. The other fields map `CrateNum` to the crate's own | |
| /// additional properties, so that effectively we can retrieve each dependent crate's `CrateSource` | |
| /// and the corresponding properties without referencing information outside of a `CrateInfo`. | |
| // rustc_codegen_cranelift needs a Clone impl for its jit mode, which isn't tested in rust CI | |
| #[derive(Clone, Debug, Encodable, Decodable)] | |
| pub struct CrateInfo { | |
| pub target_cpu: String, | |
| pub target_features: Vec<String>, | |
| pub crate_types: Vec<CrateType>, | |
| pub exported_symbols: UnordMap<CrateType, Vec<SymbolExport>>, | |
| pub linked_symbols: FxIndexMap<CrateType, Vec<(String, SymbolExportKind)>>, | |
| pub local_crate_name: Symbol, | |
| pub compiler_builtins: Option<CrateNum>, | |
| pub profiler_runtime: Option<CrateNum>, | |
| pub is_no_builtins: FxHashSet<CrateNum>, | |
| pub native_libraries: FxIndexMap<CrateNum, Vec<NativeLib>>, | |
| pub crate_name: UnordMap<CrateNum, Symbol>, | |
| pub used_libraries: Vec<NativeLib>, | |
| pub used_crate_source: UnordMap<CrateNum, Arc<CrateSource>>, | |
| pub used_crates: Vec<CrateNum>, | |
| pub dependency_formats: Arc<Dependencies>, | |
| /// EII implementations used by the link-time duplicate check, so `-Zno-link` can serialize the data needed by a | |
| /// later `-Zlink-only` invocation. | |
| pub eii_linkage: Vec<EiiLinkageInfo>, | |
| pub windows_subsystem: Option<WindowsSubsystemKind>, | |
| pub natvis_debugger_visualizers: BTreeSet<DebuggerVisualizerFile>, | |
| pub lint_level_specs: CodegenLintLevelSpecs, | |
| pub metadata_symbol: String, | |
| pub symbol_rename_suffix: String, | |
| pub each_linked_rlib_file_for_lto: Vec<PathBuf>, | |
| pub exported_symbols_for_lto: Vec<String>, | |
| } | |
| /// Target-specific options that get set in `sess`/`cfg(...)`. | |
| /// | |
| /// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen. | |
| pub struct TargetConfig { | |
| /// Options to be set in `sess.internal_target_features`. | |
| pub internal_target_features: UnordSet<Symbol>, | |
| /// Option for `cfg(target_has_reliable_f16)`, true if `f16` basic arithmetic works. | |
| pub has_reliable_f16: bool, | |
| /// Option for `cfg(target_has_reliable_f16_math)`, true if `f16` math calls work. | |
| pub has_reliable_f16_math: bool, | |
| /// Option for `cfg(target_has_reliable_f128)`, true if `f128` basic arithmetic works. | |
| pub has_reliable_f128: bool, | |
| /// Option for `cfg(target_has_reliable_f128_math)`, true if `f128` math calls work. | |
| pub has_reliable_f128_math: bool, | |
| } | |
| #[derive(Encodable, Decodable)] | |
| pub struct CompiledModules { | |
| pub modules: Vec<CompiledModule>, | |
| pub allocator_module: Option<CompiledModule>, | |
| } | |
| pub enum CodegenError { | |
| WrongFileType, | |
| EmptyVersionNumber, | |
| EncodingVersionMismatch { version_array: String, rlink_version: u32 }, | |
| RustcVersionMismatch { rustc_version: String }, | |
| CorruptFile, | |
| } | |
| pub fn provide(providers: &mut Providers) { | |
| crate::back::symbol_export::provide(providers); | |
| crate::base::provide(&mut providers.queries); | |
| crate::target_features::provide(&mut providers.queries); | |
| crate::codegen_attrs::provide(&mut providers.queries); | |
| } | |
| const RLINK_VERSION: u32 = 1; | |
| const RLINK_MAGIC: &[u8] = b"rustlink"; | |
| impl CompiledModules { | |
| pub fn serialize_rlink( | |
| sess: &Session, | |
| rlink_file: &Path, | |
| compiled_modules: &CompiledModules, | |
| crate_info: &CrateInfo, | |
| metadata: &EncodedMetadata, | |
| outputs: &OutputFilenames, | |
| ) -> Result<usize, io::Error> { | |
| let mut encoder = FileEncoder::new(rlink_file)?; | |
| encoder.emit_raw_bytes(RLINK_MAGIC); | |
| // `emit_raw_bytes` is used to make sure that the version representation does not depend on | |
| // Encoder's inner representation of `u32`. | |
| encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes()); | |
| encoder.emit_str(sess.cfg_version); | |
| Encodable::encode(compiled_modules, &mut encoder); | |
| Encodable::encode(crate_info, &mut encoder); | |
| Encodable::encode(metadata, &mut encoder); | |
| Encodable::encode(outputs, &mut encoder); | |
| encoder.finish().map_err(|(_path, err)| err) | |
| } | |
| pub fn deserialize_rlink( | |
| sess: &Session, | |
| data: Vec<u8>, | |
| ) -> Result<(Self, CrateInfo, EncodedMetadata, OutputFilenames), CodegenError> { | |
| // The Decodable machinery is not used here because it panics if the input data is invalid | |
| // and because its internal representation may change. | |
| if !data.starts_with(RLINK_MAGIC) { | |
| return Err(CodegenError::WrongFileType); | |
| } | |
| let data = &data[RLINK_MAGIC.len()..]; | |
| if data.len() < 4 { | |
| return Err(CodegenError::EmptyVersionNumber); | |
| } | |
| let mut version_array: [u8; 4] = Default::default(); | |
| version_array.copy_from_slice(&data[..4]); | |
| if u32::from_be_bytes(version_array) != RLINK_VERSION { | |
| return Err(CodegenError::EncodingVersionMismatch { | |
| version_array: String::from_utf8_lossy(&version_array).to_string(), | |
| rlink_version: RLINK_VERSION, | |
| }); | |
| } | |
| let Ok(mut decoder) = MemDecoder::new(&data[4..], 0) else { | |
| return Err(CodegenError::CorruptFile); | |
| }; | |
| let rustc_version = decoder.read_str(); | |
| if rustc_version != sess.cfg_version { | |
| return Err(CodegenError::RustcVersionMismatch { | |
| rustc_version: rustc_version.to_string(), | |
| }); | |
| } | |
| let compiled_modules = CompiledModules::decode(&mut decoder); | |
| let crate_info = CrateInfo::decode(&mut decoder); | |
| let metadata = EncodedMetadata::decode(&mut decoder); | |
| let outputs = OutputFilenames::decode(&mut decoder); | |
| Ok((compiled_modules, crate_info, metadata, outputs)) | |
| } | |
| } | |
| /// A list of lint levels used in codegen. | |
| /// | |
| /// When using `-Z link-only`, we don't have access to the tcx and must work | |
| /// solely from the `.rlink` file. `Lint`s are defined too early to be encodeable. | |
| /// Instead, encode exactly the information we need. | |
| #[derive(Copy, Clone, Debug, Encodable, Decodable)] | |
| pub struct CodegenLintLevelSpecs { | |
| linker_messages: StableLevelSpec, | |
| linker_info: StableLevelSpec, | |
| } | |
| impl CodegenLintLevelSpecs { | |
| pub fn from_tcx(tcx: TyCtxt<'_>) -> Self { | |
| Self { | |
| linker_messages: tcx.lint_level_spec_at_node(LINKER_MESSAGES, CRATE_HIR_ID), | |
| linker_info: tcx.lint_level_spec_at_node(LINKER_INFO, CRATE_HIR_ID), | |
| } | |
| } | |
| } |