| use std::sync::Arc; | |
| use std::time::Instant; | |
| #[cfg(feature = "master")] | |
| use gccjit::VarAttribute; | |
| use gccjit::{CType, FunctionType, GlobalKind}; | |
| use rustc_attr_ir::{AttributeKind, Linkage, find_attr}; | |
| use rustc_codegen_ssa::ModuleCodegen; | |
| use rustc_codegen_ssa::base::maybe_create_entry_wrapper; | |
| use rustc_codegen_ssa::mono_item::MonoItemExt; | |
| use rustc_middle::dep_graph; | |
| #[cfg(feature = "master")] | |
| use rustc_middle::mono::Visibility; | |
| use rustc_middle::ty::TyCtxt; | |
| use rustc_session::config::DebugInfo; | |
| use rustc_span::Symbol; | |
| #[cfg(feature = "master")] | |
| use rustc_target::spec::SymbolVisibility; | |
| use crate::builder::Builder; | |
| use crate::context::CodegenCx; | |
| use crate::gcc_util::new_context; | |
| use crate::{GccContext, LtoMode, SharedTargetInfo, SyncContext}; | |
| #[cfg(feature = "master")] | |
| pub fn visibility_to_gcc(visibility: Visibility) -> gccjit::Visibility { | |
| match visibility { | |
| Visibility::Default => gccjit::Visibility::Default, | |
| Visibility::Hidden => gccjit::Visibility::Hidden, | |
| Visibility::Protected => gccjit::Visibility::Protected, | |
| } | |
| } | |
| #[cfg(feature = "master")] | |
| pub fn symbol_visibility_to_gcc(visibility: SymbolVisibility) -> gccjit::Visibility { | |
| match visibility { | |
| SymbolVisibility::Hidden => gccjit::Visibility::Hidden, | |
| SymbolVisibility::Protected => gccjit::Visibility::Protected, | |
| SymbolVisibility::Interposable => gccjit::Visibility::Default, | |
| } | |
| } | |
| /// The kind of a global *definition* with an explicit `#[linkage]`. | |
| /// | |
| /// The flavours that another object file is allowed to override also need | |
| /// `global_linkage_attribute` from the caller: `GlobalKind` alone cannot express weakness. | |
| pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind { | |
| match linkage { | |
| Linkage::External => GlobalKind::Exported, | |
| // libgccjit cannot emit a definition that the linker discards in favour of the one in | |
| // another object file, so emit a private copy of it instead. | |
| Linkage::AvailableExternally | Linkage::Internal => GlobalKind::Internal, | |
| // libgccjit exposes no comdat, so `weak` stands in for the linkonce flavours. | |
| Linkage::LinkOnceAny | |
| | Linkage::LinkOnceODR | |
| | Linkage::WeakAny | |
| | Linkage::WeakODR | |
| | Linkage::ExternalWeak => GlobalKind::Exported, | |
| } | |
| } | |
| /// The attribute a global *definition* needs on top of its [`GlobalKind`] to get this linkage. | |
| #[cfg(feature = "master")] | |
| pub fn global_linkage_attribute<'gcc>(linkage: Linkage) -> Option<VarAttribute<'gcc>> { | |
| if linkage_needs_weak_attribute(linkage) { Some(VarAttribute::Weak) } else { None } | |
| } | |
| /// The type of a function *definition* with an explicit `#[linkage]`. | |
| /// | |
| /// The flavours that another object file is allowed to override also need | |
| /// `linkage_needs_weak_attribute` from the caller: `FunctionType` alone cannot express weakness. | |
| pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType { | |
| match linkage { | |
| Linkage::External => FunctionType::Exported, | |
| // libgccjit cannot emit a definition that the linker discards in favour of the one in | |
| // another object file, so emit a private copy of it instead. | |
| Linkage::AvailableExternally | Linkage::Internal => FunctionType::Internal, | |
| // libgccjit exposes no comdat, so `weak` stands in for every overridable flavour. | |
| Linkage::LinkOnceAny | |
| | Linkage::LinkOnceODR | |
| | Linkage::WeakAny | |
| | Linkage::WeakODR | |
| | Linkage::ExternalWeak => FunctionType::Exported, | |
| } | |
| } | |
| /// Whether a definition with this linkage must carry the `weak` attribute, so that a strong | |
| /// definition in another object file wins over it instead of clashing with it. | |
| #[cfg(feature = "master")] | |
| pub fn linkage_needs_weak_attribute(linkage: Linkage) -> bool { | |
| match linkage { | |
| Linkage::LinkOnceAny | |
| | Linkage::LinkOnceODR | |
| | Linkage::WeakAny | |
| | Linkage::WeakODR | |
| | Linkage::ExternalWeak => true, | |
| Linkage::External | Linkage::AvailableExternally | Linkage::Internal => false, | |
| } | |
| } | |
| pub fn compile_codegen_unit( | |
| tcx: TyCtxt<'_>, | |
| cgu_name: Symbol, | |
| target_info: SharedTargetInfo, | |
| lto_supported: bool, | |
| ) -> (ModuleCodegen<GccContext>, u64) { | |
| let prof_timer = tcx.prof.generic_activity("codegen_module"); | |
| let start_time = Instant::now(); | |
| let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); | |
| let (module, _) = tcx.dep_graph.with_task( | |
| dep_node, | |
| tcx, | |
| || module_codegen(tcx, cgu_name, target_info, lto_supported), | |
| Some(dep_graph::hash_result), | |
| ); | |
| let time_to_codegen = start_time.elapsed(); | |
| drop(prof_timer); | |
| // We assume that the cost to run GCC on a CGU is proportional to | |
| // the time we needed for codegenning it. | |
| let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64; | |
| fn module_codegen( | |
| tcx: TyCtxt<'_>, | |
| cgu_name: Symbol, | |
| target_info: SharedTargetInfo, | |
| lto_supported: bool, | |
| ) -> ModuleCodegen<GccContext> { | |
| let cgu = tcx.codegen_unit(cgu_name); | |
| // Instantiate monomorphizations without filling out definitions yet... | |
| let context = new_context(tcx.sess); | |
| // NOTE: We need to honor the `#![no_builtins]` attribute to prevent GCC from | |
| // replacing code patterns (like loops) with calls to builtins (like memset). | |
| // The `-fno-tree-loop-distribute-patterns` flag disables the loop distribution pass | |
| // that transforms loops into calls to library functions (memset, memcpy, etc.). | |
| // See GCC handling for more details: | |
| // https://github.com/rust-lang/gcc/blob/efdd0a7290c22f5438d7c5380105d353ee3e8518/gcc/c-family/c-opts.cc#L953 | |
| let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID); | |
| if find_attr!(crate_attrs, AttributeKind::NoBuiltins) { | |
| context.add_command_line_option("-fno-tree-loop-distribute-patterns"); | |
| } | |
| // NOTE: The codegen generates unreachable blocks. | |
| context.set_allow_unreachable_blocks(true); | |
| { | |
| // FIXME: to make it less error-prone (calling get_target_info() will add the flag | |
| // -fsyntax-only), forbid the compilation when get_target_info() is called on a | |
| // context. | |
| let f16_type_supported = target_info.supports_target_dependent_type(CType::Float16); | |
| let f16b_type_supported = target_info.supports_target_dependent_type(CType::BFloat16); | |
| let f32_type_supported = target_info.supports_target_dependent_type(CType::Float32); | |
| let f64_type_supported = target_info.supports_target_dependent_type(CType::Float64); | |
| let f128_type_supported = target_info.supports_target_dependent_type(CType::Float128); | |
| let u128_type_supported = target_info.supports_target_dependent_type(CType::UInt128t); | |
| // FIXME: improve this to avoid passing that many arguments. | |
| let mut cx = CodegenCx::new( | |
| &context, | |
| cgu, | |
| tcx, | |
| u128_type_supported, | |
| f16_type_supported, | |
| f16b_type_supported, | |
| f32_type_supported, | |
| f64_type_supported, | |
| f128_type_supported, | |
| ); | |
| let mono_items = cgu.items_in_deterministic_order(tcx); | |
| for &(mono_item, data) in &mono_items { | |
| mono_item.predefine::<Builder<'_, '_, '_>>( | |
| &mut cx, | |
| cgu_name.as_str(), | |
| data.linkage, | |
| data.visibility, | |
| ); | |
| } | |
| // ... and now that we have everything pre-defined, fill out those definitions. | |
| for &(mono_item, item_data) in &mono_items { | |
| mono_item.define::<Builder<'_, '_, '_>>(&mut cx, cgu_name.as_str(), item_data); | |
| // Now that this function's blocks all exist, fill in the cleanup | |
| // regions reconstructed from MIR while lowering its `invoke`s. | |
| #[cfg(feature = "master")] | |
| cx.populate_cleanup_regions(); | |
| } | |
| // If this codegen unit contains the main function, also create the | |
| // wrapper here | |
| maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx, cx.codegen_unit); | |
| // Finalize debuginfo | |
| if cx.sess().opts.debuginfo != DebugInfo::None { | |
| cx.debuginfo_finalize(); | |
| } | |
| } | |
| ModuleCodegen::new_regular( | |
| cgu_name.to_string(), | |
| GccContext { | |
| context: Arc::new(SyncContext::new(context)), | |
| relocation_model: tcx.sess.relocation_model(), | |
| lto_supported, | |
| lto_mode: LtoMode::None, | |
| temp_dir: None, | |
| }, | |
| ) | |
| } | |
| (module, cost) | |
| } |