rust-lang/rust · #163003

cg_llvm: Move all code out of the crate root

Zalathar · merged Sep 19, 202610 files · 509 + / 500
compiler/rustc_codegen_llvm/src/allocator.rs2 + / 1
@@ -12,9 +12,10 @@ use rustc_symbol_mangling::mangle_internal_symbol;  use crate::attributes::llfn_attrs_from_instance; use crate::builder::SBuilder;+use crate::context::SimpleCx; use crate::declare::declare_simple_fn; use crate::llvm::{self, FromGeneric, TRUE, Type};-use crate::{SimpleCx, attributes, debuginfo};+use crate::{attributes, debuginfo};  pub(crate) unsafe fn codegen(     tcx: TyCtxt<'_>,
compiler/rustc_codegen_llvm/src/attributes.rs2 + / 1
@@ -8,6 +8,7 @@ use rustc_middle::middle::codegen_fn_attrs::{ }; use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_sanitizers::ignorelist::SanitizerIgnoreList;+use rustc_session::Session; use rustc_session::config::{     BranchProtection, FunctionReturn, InstrumentMcount, InstrumentMcountOpts, OptLevel, PAuthKey,     PacRet,@@ -23,7 +24,7 @@ use crate::llvm::AttributePlace::Function; use crate::llvm::{     self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects, Value, };-use crate::{Session, attributes, llvm_util};+use crate::{attributes, llvm_util};  pub(crate) fn apply_to_llfn(llfn: &Value, idx: AttributePlace, attrs: &[&Attribute]) {     if !attrs.is_empty() {
compiler/rustc_codegen_llvm/src/back/llvm_backend.rsadded494 + / 0
@@ -0,0 +1,494 @@+//! Module containing [`LlvmCodegenBackend`], which implements [`CodegenBackend`]+//! and related traits for the LLVM codegen backend.++use std::any::Any;+use std::ffi::CStr;+use std::mem::ManuallyDrop;+use std::path::PathBuf;++use rustc_ast::expand::allocator::AllocatorMethod;+use rustc_codegen_ssa::back::lto::ThinModule;+use rustc_codegen_ssa::back::write::{+    CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryConfig,+    TargetMachineFactoryFn, ThinLtoInput,+};+use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods};+use rustc_codegen_ssa::{CompiledModule, CompiledModules, CrateInfo, ModuleCodegen, TargetConfig};+use rustc_data_structures::profiling::SelfProfilerRef;+use rustc_errors::{DiagCtxt, DiagCtxtHandle};+use rustc_metadata::EncodedMetadata;+use rustc_middle::dep_graph::{WorkProduct, WorkProductMap};+use rustc_middle::ty::TyCtxt;+use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest};+use rustc_session::{CodegenBackendInit, EarlySession, IncrCompSession, Session};+use rustc_span::{Symbol, sym};+use rustc_target::spec::{RelocModel, TlsModel};++use crate::back::owned_target_machine::OwnedTargetMachine;+use crate::back::write::{create_informational_target_machine, create_target_machine};+use crate::context::{self, SimpleCx};+use crate::llvm::{self, ToLlvmBool};+use crate::llvm_util::{self, target_config};+use crate::{allocator, back, base};++#[derive(Clone)]+pub struct LlvmCodegenBackend(());++struct TimeTraceProfiler {}++impl TimeTraceProfiler {+    fn new() -> Self {+        unsafe { llvm::LLVMRustTimeTraceProfilerInitialize() }+        TimeTraceProfiler {}+    }+}++impl Drop for TimeTraceProfiler {+    fn drop(&mut self) {+        unsafe { llvm::LLVMRustTimeTraceProfilerFinishThread() }+    }+}++impl ExtraBackendMethods for LlvmCodegenBackend {+    type Module = ModuleLlvm;++    fn codegen_allocator<'tcx>(+        &self,+        tcx: TyCtxt<'tcx>,+        module_name: &str,+        methods: &[AllocatorMethod],+    ) -> ModuleLlvm {+        let module_llvm = ModuleLlvm::new_metadata(tcx, module_name);+        let cx =+            SimpleCx::new(module_llvm.llmod(), &module_llvm.llcx, tcx.data_layout.pointer_size());+        unsafe {+            allocator::codegen(tcx, cx, module_name, methods);+        }+        module_llvm+    }+    fn compile_codegen_unit(+        &self,+        tcx: TyCtxt<'_>,+        cgu_name: Symbol,+        bitcode_needed: bool,+    ) -> (ModuleCodegen<ModuleLlvm>, u64) {+        base::compile_codegen_unit(tcx, cgu_name, bitcode_needed)+    }+}++impl WriteBackendMethods for LlvmCodegenBackend {+    type Module = ModuleLlvm;+    type ModuleBuffer = back::lto::ModuleBuffer;+    type TargetMachine = OwnedTargetMachine;+    type ThinData = back::lto::ThinData;++    fn thread_profiler() -> Box<dyn Any> {+        Box::new(TimeTraceProfiler::new())+    }+    fn target_machine_factory(+        &self,+        sess: &Session,+        optlvl: OptLevel,+    ) -> TargetMachineFactoryFn<Self> {+        back::write::target_machine_factory(sess, optlvl)+    }+    fn optimize_and_codegen_fat_lto(+        sess: &Session,+        cgcx: &CodegenContext,+        shared_emitter: &SharedEmitter,+        tm_factory: TargetMachineFactoryFn<LlvmCodegenBackend>,+        exported_symbols_for_lto: &[String],+        each_linked_rlib_for_lto: &[PathBuf],+        modules: Vec<FatLtoInput<Self>>,+    ) -> CompiledModule {+        let mut module = back::lto::run_fat(+            cgcx,+            &sess.prof,+            shared_emitter,+            tm_factory,+            exported_symbols_for_lto,+            each_linked_rlib_for_lto,+            modules,+        );++        let dcx = DiagCtxt::new(Box::new(shared_emitter.clone()));+        let dcx = dcx.handle();+        back::lto::run_pass_manager(cgcx, &sess.prof, dcx, &mut module, false);++        back::write::codegen(cgcx, &sess.prof, shared_emitter, module, &cgcx.module_config)+    }+    fn run_thin_lto(+        cgcx: &CodegenContext,+        prof: &SelfProfilerRef,+        dcx: DiagCtxtHandle<'_>,+        exported_symbols_for_lto: &[String],+        each_linked_rlib_for_lto: &[PathBuf],+        modules: Vec<ThinLtoInput<Self>>,+    ) -> (Vec<ThinModule<Self>>, Vec<WorkProduct>) {+        back::lto::run_thin(+            cgcx,+            prof,+            dcx,+            exported_symbols_for_lto,+            each_linked_rlib_for_lto,+            modules,+        )+    }+    fn optimize(+        cgcx: &CodegenContext,+        prof: &SelfProfilerRef,+        shared_emitter: &SharedEmitter,+        module: &mut ModuleCodegen<Self::Module>,+        config: &ModuleConfig,+    ) {+        back::write::optimize(cgcx, prof, shared_emitter, module, config)+    }+    fn optimize_and_codegen_thin(+        cgcx: &CodegenContext,+        prof: &SelfProfilerRef,+        shared_emitter: &SharedEmitter,+        tm_factory: TargetMachineFactoryFn<LlvmCodegenBackend>,+        thin: ThinModule<Self>,+    ) -> CompiledModule {+        back::lto::optimize_and_codegen_thin_module(cgcx, prof, shared_emitter, tm_factory, thin)+    }+    fn codegen(+        cgcx: &CodegenContext,+        prof: &SelfProfilerRef,+        shared_emitter: &SharedEmitter,+        module: ModuleCodegen<Self::Module>,+        config: &ModuleConfig,+    ) -> CompiledModule {+        back::write::codegen(cgcx, prof, shared_emitter, module, config)+    }+    fn serialize_module(module: Self::Module, is_thin: bool) -> Self::ModuleBuffer {+        back::lto::ModuleBuffer::new(module.llmod(), is_thin)+    }+}++impl LlvmCodegenBackend {+    pub fn new() -> Box<dyn CodegenBackend> {+        Box::new(LlvmCodegenBackend(()))+    }+}++impl CodegenBackend for LlvmCodegenBackend {+    fn name(&self) -> &'static str {+        "llvm"+    }++    fn init(&mut self, sess: &EarlySession) -> CodegenBackendInit {+        llvm_util::init(sess); // Make sure llvm is inited++        let global_backend_features =+            llvm_util::global_llvm_features(sess, /* for_cfg */ false);++        // autodiff is based on Enzyme, a library which we might not have available, when it was+        // neither build, nor downloaded via rustup. If autodiff is used, but not available we emit+        // an early error here and abort compilation.+        {+            use rustc_session::config::AutoDiff;++            use crate::back::lto::enable_autodiff_settings;+            if sess.opts.unstable_opts.autodiff.contains(&AutoDiff::Enable) {+                match llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) {+                    Ok(_) => {}+                    Err(llvm::EnzymeLibraryError::NotFound { err }) => {+                        sess.dcx().emit_fatal(crate::diagnostics::AutoDiffComponentMissing { err });+                    }+                    Err(llvm::EnzymeLibraryError::LoadFailed { err }) => {+                        sess.dcx()+                            .emit_fatal(crate::diagnostics::AutoDiffComponentUnavailable { err });+                    }+                }+                enable_autodiff_settings(&sess.opts.unstable_opts.autodiff);+            }+        }++        // Intrinsics whose fallback body will not be used by the LLVM backend.+        let replaced_intrinsics = {+            #[rustfmt::skip]+            let mut will_not_use_fallback = vec![+                // These are mapped to LLVM intrinsics instead.+                sym::unchecked_funnel_shl,+                sym::unchecked_funnel_shr,+                sym::carrying_mul_add,+                sym::integer_max,+                sym::integer_min,++                // Fallback via libm, but the LLVM intrinsic is used instead.+                sym::sin,+                sym::cos,+                sym::powf16, sym::powf32, sym::powf64,+                sym::exp,+                sym::exp2,+                sym::log,+                sym::log10,+                sym::log2,++                // Fallback via f32 or f64, but the LLVM intrinsic is used instead.+                sym::floorf16, sym::ceilf16, sym::truncf16,+                sym::round_ties_even_f16, sym::roundf16,+                sym::sqrtf16, sym::powif16,+                sym::fmaf16,++                sym::copysignf16, sym::copysignf32, sym::copysignf64, sym::copysignf128,+            ];++            if llvm_util::get_version() >= (22, 0, 0) {+                will_not_use_fallback.push(sym::carryless_mul);+            }++            will_not_use_fallback+        };++        // `type_id_eq` is a safe choice since *all* backends use the fallback body for that. When+        // adding more intrinsics, keep in mind that the distributed standard library is compiled+        // with the LLVM backend but might later be included in a project built with cranelift or+        // GCC. Adding an intrinsic here can therefore mean the fallback body is used with+        // cranelift/GCC even if they have dedicated implementations.+        let fallback_intrinsics = vec![sym::type_id_eq];++        CodegenBackendInit {+            global_backend_features,+            replaced_intrinsics,+            fallback_intrinsics,+            thin_lto_supported: true,+        }+    }++    fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) {+        use std::fmt::Write;+        match req.kind {+            PrintKind::RelocationModels => {+                writeln!(out, "Available relocation models:").unwrap();+                for name in RelocModel::ALL.iter().map(RelocModel::desc).chain(["default"]) {+                    writeln!(out, "    {name}").unwrap();+                }+                writeln!(out).unwrap();+            }+            PrintKind::CodeModels => {+                writeln!(out, "Available code models:").unwrap();+                for name in &["tiny", "small", "kernel", "medium", "large"] {+                    writeln!(out, "    {name}").unwrap();+                }+                writeln!(out).unwrap();+            }+            PrintKind::TlsModels => {+                writeln!(out, "Available TLS models:").unwrap();+                for name in TlsModel::ALL.iter().map(TlsModel::desc) {+                    writeln!(out, "    {name}").unwrap();+                }+                writeln!(out).unwrap();+            }+            PrintKind::StackProtectorStrategies => {+                writeln!(+                    out,+                    r#"Available stack protector strategies:+    all+        Generate stack canaries in all functions.++    strong+        Generate stack canaries in a function if it either:+        - has a local variable of `[T; N]` type, regardless of `T` and `N`+        - takes the address of a local variable.++          (Note that a local variable being borrowed is not equivalent to its+          address being taken: e.g. some borrows may be removed by optimization,+          while by-value argument passing may be implemented with reference to a+          local stack variable in the ABI.)++    basic+        Generate stack canaries in functions with local variables of `[T; N]`+        type, where `T` is byte-sized and `N` >= 8.++    none+        Do not generate stack canaries.+"#+                )+                .unwrap();+            }+            _other => llvm_util::print(req, out, sess),+        }+    }++    fn print_passes(&self) {+        llvm_util::print_passes();+    }++    fn print_version(&self) {+        llvm_util::print_version();+    }++    fn has_zstd(&self) -> bool {+        llvm::LLVMRustLLVMHasZstdCompression()+    }++    fn has_mnemonic(&self, sess: &Session, mnemonic: &str) -> bool {+        llvm_util::target_has_mnemonic(sess, mnemonic)+    }++    fn target_config(&self, sess: &EarlySession) -> TargetConfig {+        target_config(sess)+    }++    fn target_cpu(&self, sess: &Session) -> String {+        crate::llvm_util::target_cpu(sess).to_string()+    }++    fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box<dyn Any> {+        use rustc_session::config::Offload;++        if tcx.sess.opts.unstable_opts.offload.iter().any(|o| matches!(o, Offload::Device(_)))+            || tcx.sess.opts.unstable_opts.offload.iter().any(|o| matches!(o, Offload::Host(_)))+        {+            match llvm::RustOffloadWrapper::get_or_init(&tcx.sess.opts.sysroot) {+                Ok(_) => {}+                Err(llvm::RustOffloadLibraryError::NotFound { err }) => {+                    tcx.sess+                        .dcx()+                        .emit_fatal(crate::diagnostics::RustOffloadComponentMissing { err });+                }+                Err(llvm::RustOffloadLibraryError::LoadFailed { err }) => {+                    tcx.sess+                        .dcx()+                        .emit_fatal(crate::diagnostics::RustOffloadComponentUnavailable { err });+                }+            }+        }++        Box::new(rustc_codegen_ssa::base::codegen_crate(LlvmCodegenBackend(()), tcx))+    }++    fn join_codegen(+        &self,+        ongoing_codegen: Box<dyn Any>,+        sess: &Session,+        incr_comp_session: Option<&IncrCompSession>,+        outputs: &OutputFilenames,+        crate_info: &CrateInfo,+    ) -> (CompiledModules, WorkProductMap) {+        let (compiled_modules, work_products) = ongoing_codegen+            .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()+            .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")+            .join(sess, incr_comp_session, crate_info);++        if sess.opts.unstable_opts.llvm_time_trace {+            sess.time("llvm_dump_timing_file", || {+                let file_name = outputs.with_extension("llvm_timings.json");+                llvm_util::time_trace_profiler_finish(&file_name);+            });+        }++        (compiled_modules, work_products)+    }++    fn print_pass_timings(&self) {+        let timings = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintPassTimings(s) }).unwrap();+        print!("{timings}");+    }++    fn print_statistics(&self) {+        let stats = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatistics(s) }).unwrap();+        print!("{stats}");+    }++    fn print_statistics_json(&self) -> String {+        llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatisticsJSON(s) }).unwrap()+    }++    fn link(+        &self,+        sess: &Session,+        compiled_modules: CompiledModules,+        crate_info: CrateInfo,+        metadata: EncodedMetadata,+        outputs: &OutputFilenames,+    ) {+        use rustc_codegen_ssa::back::link::link_binary;++        use crate::back::archive::LlvmArchiveBuilderBuilder;++        // Run the linker on any artifacts that resulted from the LLVM run.+        // This should produce either a finished executable or library.+        link_binary(+            sess,+            &LlvmArchiveBuilderBuilder,+            compiled_modules,+            crate_info,+            metadata,+            outputs,+            self.name(),+        );+    }+}++pub struct ModuleLlvm {+    pub(crate) llcx: &'static mut llvm::Context,+    llmod_raw: *const llvm::Module,++    // This field is `ManuallyDrop` because it is important that the `TargetMachine`+    // is disposed prior to the `Context` being disposed otherwise UAFs can occur.+    pub(crate) tm: ManuallyDrop<OwnedTargetMachine>,+}++unsafe impl Send for ModuleLlvm {}+unsafe impl Sync for ModuleLlvm {}++impl ModuleLlvm {+    pub(crate) fn new(tcx: TyCtxt<'_>, mod_name: &str) -> Self {+        unsafe {+            let llcx = llvm::LLVMContextCreate();+            llvm::LLVMContextSetDiscardValueNames(llcx, tcx.sess.fewer_names().to_llvm_bool());+            let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;+            ModuleLlvm {+                llmod_raw,+                llcx,+                tm: ManuallyDrop::new(create_target_machine(tcx, mod_name)),+            }+        }+    }++    pub(crate) fn new_metadata(tcx: TyCtxt<'_>, mod_name: &str) -> Self {+        unsafe {+            let llcx = llvm::LLVMContextCreate();+            llvm::LLVMContextSetDiscardValueNames(llcx, tcx.sess.fewer_names().to_llvm_bool());+            let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;+            ModuleLlvm {+                llmod_raw,+                llcx,+                tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)),+            }+        }+    }++    pub(crate) fn parse(+        cgcx: &CodegenContext,+        tm_factory: TargetMachineFactoryFn<LlvmCodegenBackend>,+        name: &CStr,+        buffer: &[u8],+        dcx: DiagCtxtHandle<'_>,+    ) -> Self {+        unsafe {+            let llcx = llvm::LLVMContextCreate();+            llvm::LLVMContextSetDiscardValueNames(llcx, cgcx.fewer_names.to_llvm_bool());+            let llmod_raw = back::lto::parse_module(llcx, name, buffer, dcx);+            let tm = tm_factory(dcx, TargetMachineFactoryConfig::new(cgcx, name.to_str().unwrap()));++            ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) }+        }+    }++    pub(crate) fn llmod(&self) -> &llvm::Module {+        unsafe { &*self.llmod_raw }+    }+}++impl Drop for ModuleLlvm {+    fn drop(&mut self) {+        unsafe {+            ManuallyDrop::drop(&mut self.tm);+            llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));+        }+    }+}
compiler/rustc_codegen_llvm/src/back/mod.rs1 + / 0
@@ -1,4 +1,5 @@ pub(crate) mod archive;+pub(crate) mod llvm_backend; pub(crate) mod lto; pub(crate) mod owned_mc_subtarget_info; pub(crate) mod owned_target_machine;
compiler/rustc_codegen_llvm/src/back/write.rs2 + / 1
@@ -34,14 +34,15 @@ use crate::back::profiling::{ use crate::builder::SBuilder; use crate::builder::gpu_offload::scalar_width; use crate::common::AsCCharPtr;+use crate::context::SimpleCx; use crate::diagnostics::{     CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, ParseTargetMachineConfig,     UnsupportedCompression, WithLlvmError, WriteBytecode, }; use crate::llvm::diagnostic::OptimizationDiagnosticKind::*; use crate::llvm::{self, DiagnosticInfo}; use crate::type_::llvm_type_ptr;-use crate::{LlvmCodegenBackend, ModuleLlvm, SimpleCx, attributes, base, common, llvm_util};+use crate::{LlvmCodegenBackend, ModuleLlvm, attributes, base, common, llvm_util};  pub(crate) fn llvm_err<'a>(dcx: DiagCtxtHandle<'_>, err: LlvmError<'a>) -> ! {     match llvm::last_error() {
compiler/rustc_codegen_llvm/src/base.rs1 + / 2
@@ -27,12 +27,11 @@ use rustc_session::config::{DebugInfo, Offload}; use rustc_span::Symbol; use rustc_target::spec::SanitizerSet; -use super::ModuleLlvm;-use crate::attributes; use crate::builder::Builder; use crate::builder::gpu_offload::OffloadGlobals; use crate::context::CodegenCx; use crate::llvm::{self, Value};+use crate::{ModuleLlvm, attributes};  pub(crate) struct ValueIter<'ll> {     cur: Option<&'ll Value>,
compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs2 + / 1
@@ -10,11 +10,12 @@ use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods, ReturnSl use rustc_middle::ty::offload_meta::{MappingFlags, OffloadMetadata, OffloadSize}; use rustc_span::bug; +use crate::attributes; use crate::builder::Builder; use crate::common::CodegenCx;+use crate::context::SimpleCx; use crate::llvm::AttributePlace::Function; use crate::llvm::{self, Linkage, Type, Value};-use crate::{SimpleCx, attributes};  // LLVM kernel-independent globals required for offloading pub(crate) struct OffloadGlobals<'ll> {
compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs2 + / 1
@@ -11,7 +11,8 @@ use tracing::debug; use crate::common::CodegenCx; use crate::coverageinfo::llvm_cov; use crate::coverageinfo::mapgen::covfun::prepare_covfun_record;-use crate::{TryFromU32, llvm};+use crate::llvm;+use crate::macros::TryFromU32;  mod covfun; mod spans;
compiler/rustc_codegen_llvm/src/lib.rs1 + / 492
@@ -15,34 +15,7 @@ #![feature(try_blocks)] // tidy-alphabetical-end -use std::any::Any;-use std::ffi::CStr;-use std::mem::ManuallyDrop;-use std::path::PathBuf;--use back::owned_target_machine::OwnedTargetMachine;-use back::write::{create_informational_target_machine, create_target_machine};-use context::SimpleCx;-use llvm_util::target_config;-use rustc_ast::expand::allocator::AllocatorMethod;-use rustc_codegen_ssa::back::lto::ThinModule;-use rustc_codegen_ssa::back::write::{-    CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryConfig,-    TargetMachineFactoryFn, ThinLtoInput,-};-use rustc_codegen_ssa::traits::*;-use rustc_codegen_ssa::{CompiledModule, CompiledModules, CrateInfo, ModuleCodegen, TargetConfig};-use rustc_data_structures::profiling::SelfProfilerRef;-use rustc_errors::{DiagCtxt, DiagCtxtHandle};-use rustc_metadata::EncodedMetadata;-use rustc_middle::dep_graph::{WorkProduct, WorkProductMap};-use rustc_middle::ty::TyCtxt;-use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest};-use rustc_session::{CodegenBackendInit, EarlySession, IncrCompSession, Session};-use rustc_span::{Symbol, sym};-use rustc_target::spec::{RelocModel, TlsModel};--use crate::llvm::ToLlvmBool;+pub use crate::back::llvm_backend::{LlvmCodegenBackend, ModuleLlvm};  mod abi; mod allocator;@@ -69,467 +42,3 @@ mod type_of; mod typetree; mod va_arg; mod value;--pub(crate) use macros::TryFromU32;--#[derive(Clone)]-pub struct LlvmCodegenBackend(());--struct TimeTraceProfiler {}--impl TimeTraceProfiler {-    fn new() -> Self {-        unsafe { llvm::LLVMRustTimeTraceProfilerInitialize() }-        TimeTraceProfiler {}-    }-}--impl Drop for TimeTraceProfiler {-    fn drop(&mut self) {-        unsafe { llvm::LLVMRustTimeTraceProfilerFinishThread() }-    }-}--impl ExtraBackendMethods for LlvmCodegenBackend {-    type Module = ModuleLlvm;--    fn codegen_allocator<'tcx>(-        &self,-        tcx: TyCtxt<'tcx>,-        module_name: &str,-        methods: &[AllocatorMethod],-    ) -> ModuleLlvm {-        let module_llvm = ModuleLlvm::new_metadata(tcx, module_name);-        let cx =-            SimpleCx::new(module_llvm.llmod(), &module_llvm.llcx, tcx.data_layout.pointer_size());-        unsafe {-            allocator::codegen(tcx, cx, module_name, methods);-        }-        module_llvm-    }-    fn compile_codegen_unit(-        &self,-        tcx: TyCtxt<'_>,-        cgu_name: Symbol,-        bitcode_needed: bool,-    ) -> (ModuleCodegen<ModuleLlvm>, u64) {-        base::compile_codegen_unit(tcx, cgu_name, bitcode_needed)-    }-}--impl WriteBackendMethods for LlvmCodegenBackend {-    type Module = ModuleLlvm;-    type ModuleBuffer = back::lto::ModuleBuffer;-    type TargetMachine = OwnedTargetMachine;-    type ThinData = back::lto::ThinData;--    fn thread_profiler() -> Box<dyn Any> {-        Box::new(TimeTraceProfiler::new())-    }-    fn target_machine_factory(-        &self,-        sess: &Session,-        optlvl: OptLevel,-    ) -> TargetMachineFactoryFn<Self> {-        back::write::target_machine_factory(sess, optlvl)-    }-    fn optimize_and_codegen_fat_lto(-        sess: &Session,-        cgcx: &CodegenContext,-        shared_emitter: &SharedEmitter,-        tm_factory: TargetMachineFactoryFn<LlvmCodegenBackend>,-        exported_symbols_for_lto: &[String],-        each_linked_rlib_for_lto: &[PathBuf],-        modules: Vec<FatLtoInput<Self>>,-    ) -> CompiledModule {-        let mut module = back::lto::run_fat(-            cgcx,-            &sess.prof,-            shared_emitter,-            tm_factory,-            exported_symbols_for_lto,-            each_linked_rlib_for_lto,-            modules,-        );--        let dcx = DiagCtxt::new(Box::new(shared_emitter.clone()));-        let dcx = dcx.handle();-        back::lto::run_pass_manager(cgcx, &sess.prof, dcx, &mut module, false);--        back::write::codegen(cgcx, &sess.prof, shared_emitter, module, &cgcx.module_config)-    }-    fn run_thin_lto(-        cgcx: &CodegenContext,-        prof: &SelfProfilerRef,-        dcx: DiagCtxtHandle<'_>,-        exported_symbols_for_lto: &[String],-        each_linked_rlib_for_lto: &[PathBuf],-        modules: Vec<ThinLtoInput<Self>>,-    ) -> (Vec<ThinModule<Self>>, Vec<WorkProduct>) {-        back::lto::run_thin(-            cgcx,-            prof,-            dcx,-            exported_symbols_for_lto,-            each_linked_rlib_for_lto,-            modules,-        )-    }-    fn optimize(-        cgcx: &CodegenContext,-        prof: &SelfProfilerRef,-        shared_emitter: &SharedEmitter,-        module: &mut ModuleCodegen<Self::Module>,-        config: &ModuleConfig,-    ) {-        back::write::optimize(cgcx, prof, shared_emitter, module, config)-    }-    fn optimize_and_codegen_thin(-        cgcx: &CodegenContext,-        prof: &SelfProfilerRef,-        shared_emitter: &SharedEmitter,-        tm_factory: TargetMachineFactoryFn<LlvmCodegenBackend>,-        thin: ThinModule<Self>,-    ) -> CompiledModule {-        back::lto::optimize_and_codegen_thin_module(cgcx, prof, shared_emitter, tm_factory, thin)-    }-    fn codegen(-        cgcx: &CodegenContext,-        prof: &SelfProfilerRef,-        shared_emitter: &SharedEmitter,-        module: ModuleCodegen<Self::Module>,-        config: &ModuleConfig,-    ) -> CompiledModule {-        back::write::codegen(cgcx, prof, shared_emitter, module, config)-    }-    fn serialize_module(module: Self::Module, is_thin: bool) -> Self::ModuleBuffer {-        back::lto::ModuleBuffer::new(module.llmod(), is_thin)-    }-}--impl LlvmCodegenBackend {-    pub fn new() -> Box<dyn CodegenBackend> {-        Box::new(LlvmCodegenBackend(()))-    }-}--impl CodegenBackend for LlvmCodegenBackend {-    fn name(&self) -> &'static str {-        "llvm"-    }--    fn init(&mut self, sess: &EarlySession) -> CodegenBackendInit {-        llvm_util::init(sess); // Make sure llvm is inited--        let global_backend_features =-            llvm_util::global_llvm_features(sess, /* for_cfg */ false);--        // autodiff is based on Enzyme, a library which we might not have available, when it was-        // neither build, nor downloaded via rustup. If autodiff is used, but not available we emit-        // an early error here and abort compilation.-        {-            use rustc_session::config::AutoDiff;--            use crate::back::lto::enable_autodiff_settings;-            if sess.opts.unstable_opts.autodiff.contains(&AutoDiff::Enable) {-                match llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) {-                    Ok(_) => {}-                    Err(llvm::EnzymeLibraryError::NotFound { err }) => {-                        sess.dcx().emit_fatal(crate::diagnostics::AutoDiffComponentMissing { err });-                    }-                    Err(llvm::EnzymeLibraryError::LoadFailed { err }) => {-                        sess.dcx()-                            .emit_fatal(crate::diagnostics::AutoDiffComponentUnavailable { err });-                    }-                }-                enable_autodiff_settings(&sess.opts.unstable_opts.autodiff);-            }-        }--        // Intrinsics whose fallback body will not be used by the LLVM backend.-        let replaced_intrinsics = {-            #[rustfmt::skip]-            let mut will_not_use_fallback = vec![-                // These are mapped to LLVM intrinsics instead.-                sym::unchecked_funnel_shl,-                sym::unchecked_funnel_shr,-                sym::carrying_mul_add,-                sym::integer_max,-                sym::integer_min,--                // Fallback via libm, but the LLVM intrinsic is used instead.-                sym::sin,-                sym::cos,-                sym::powf16, sym::powf32, sym::powf64,-                sym::exp,-                sym::exp2,-                sym::log,-                sym::log10,-                sym::log2,--                // Fallback via f32 or f64, but the LLVM intrinsic is used instead.-                sym::floorf16, sym::ceilf16, sym::truncf16,-                sym::round_ties_even_f16, sym::roundf16,-                sym::sqrtf16, sym::powif16,-                sym::fmaf16,--                sym::copysignf16, sym::copysignf32, sym::copysignf64, sym::copysignf128,-            ];--            if llvm_util::get_version() >= (22, 0, 0) {-                will_not_use_fallback.push(sym::carryless_mul);-            }--            will_not_use_fallback-        };--        // `type_id_eq` is a safe choice since *all* backends use the fallback body for that. When-        // adding more intrinsics, keep in mind that the distributed standard library is compiled-        // with the LLVM backend but might later be included in a project built with cranelift or-        // GCC. Adding an intrinsic here can therefore mean the fallback body is used with-        // cranelift/GCC even if they have dedicated implementations.-        let fallback_intrinsics = vec![sym::type_id_eq];--        CodegenBackendInit {-            global_backend_features,-            replaced_intrinsics,-            fallback_intrinsics,-            thin_lto_supported: true,-        }-    }--    fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) {-        use std::fmt::Write;-        match req.kind {-            PrintKind::RelocationModels => {-                writeln!(out, "Available relocation models:").unwrap();-                for name in RelocModel::ALL.iter().map(RelocModel::desc).chain(["default"]) {-                    writeln!(out, "    {name}").unwrap();-                }-                writeln!(out).unwrap();-            }-            PrintKind::CodeModels => {-                writeln!(out, "Available code models:").unwrap();-                for name in &["tiny", "small", "kernel", "medium", "large"] {-                    writeln!(out, "    {name}").unwrap();-                }-                writeln!(out).unwrap();-            }-            PrintKind::TlsModels => {-                writeln!(out, "Available TLS models:").unwrap();-                for name in TlsModel::ALL.iter().map(TlsModel::desc) {-                    writeln!(out, "    {name}").unwrap();-                }-                writeln!(out).unwrap();-            }-            PrintKind::StackProtectorStrategies => {-                writeln!(-                    out,-                    r#"Available stack protector strategies:-    all-        Generate stack canaries in all functions.--    strong-        Generate stack canaries in a function if it either:-        - has a local variable of `[T; N]` type, regardless of `T` and `N`-        - takes the address of a local variable.--          (Note that a local variable being borrowed is not equivalent to its-          address being taken: e.g. some borrows may be removed by optimization,-          while by-value argument passing may be implemented with reference to a-          local stack variable in the ABI.)--    basic-        Generate stack canaries in functions with local variables of `[T; N]`-        type, where `T` is byte-sized and `N` >= 8.--    none-        Do not generate stack canaries.-"#-                )-                .unwrap();-            }-            _other => llvm_util::print(req, out, sess),-        }-    }--    fn print_passes(&self) {-        llvm_util::print_passes();-    }--    fn print_version(&self) {-        llvm_util::print_version();-    }--    fn has_zstd(&self) -> bool {-        llvm::LLVMRustLLVMHasZstdCompression()-    }--    fn has_mnemonic(&self, sess: &Session, mnemonic: &str) -> bool {-        llvm_util::target_has_mnemonic(sess, mnemonic)-    }--    fn target_config(&self, sess: &EarlySession) -> TargetConfig {-        target_config(sess)-    }--    fn target_cpu(&self, sess: &Session) -> String {-        crate::llvm_util::target_cpu(sess).to_string()-    }--    fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box<dyn Any> {-        use rustc_session::config::Offload;--        if tcx.sess.opts.unstable_opts.offload.iter().any(|o| matches!(o, Offload::Device(_)))-            || tcx.sess.opts.unstable_opts.offload.iter().any(|o| matches!(o, Offload::Host(_)))-        {-            match llvm::RustOffloadWrapper::get_or_init(&tcx.sess.opts.sysroot) {-                Ok(_) => {}-                Err(llvm::RustOffloadLibraryError::NotFound { err }) => {-                    tcx.sess-                        .dcx()-                        .emit_fatal(crate::diagnostics::RustOffloadComponentMissing { err });-                }-                Err(llvm::RustOffloadLibraryError::LoadFailed { err }) => {-                    tcx.sess-                        .dcx()-                        .emit_fatal(crate::diagnostics::RustOffloadComponentUnavailable { err });-                }-            }-        }--        Box::new(rustc_codegen_ssa::base::codegen_crate(LlvmCodegenBackend(()), tcx))-    }--    fn join_codegen(-        &self,-        ongoing_codegen: Box<dyn Any>,-        sess: &Session,-        incr_comp_session: Option<&IncrCompSession>,-        outputs: &OutputFilenames,-        crate_info: &CrateInfo,-    ) -> (CompiledModules, WorkProductMap) {-        let (compiled_modules, work_products) = ongoing_codegen-            .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()-            .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")-            .join(sess, incr_comp_session, crate_info);--        if sess.opts.unstable_opts.llvm_time_trace {-            sess.time("llvm_dump_timing_file", || {-                let file_name = outputs.with_extension("llvm_timings.json");-                llvm_util::time_trace_profiler_finish(&file_name);-            });-        }--        (compiled_modules, work_products)-    }--    fn print_pass_timings(&self) {-        let timings = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintPassTimings(s) }).unwrap();-        print!("{timings}");-    }--    fn print_statistics(&self) {-        let stats = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatistics(s) }).unwrap();-        print!("{stats}");-    }--    fn print_statistics_json(&self) -> String {-        llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatisticsJSON(s) }).unwrap()-    }--    fn link(-        &self,-        sess: &Session,-        compiled_modules: CompiledModules,-        crate_info: CrateInfo,-        metadata: EncodedMetadata,-        outputs: &OutputFilenames,-    ) {-        use rustc_codegen_ssa::back::link::link_binary;--        use crate::back::archive::LlvmArchiveBuilderBuilder;--        // Run the linker on any artifacts that resulted from the LLVM run.-        // This should produce either a finished executable or library.-        link_binary(-            sess,-            &LlvmArchiveBuilderBuilder,-            compiled_modules,-            crate_info,-            metadata,-            outputs,-            self.name(),-        );-    }-}--pub struct ModuleLlvm {-    llcx: &'static mut llvm::Context,-    llmod_raw: *const llvm::Module,--    // This field is `ManuallyDrop` because it is important that the `TargetMachine`-    // is disposed prior to the `Context` being disposed otherwise UAFs can occur.-    tm: ManuallyDrop<OwnedTargetMachine>,-}--unsafe impl Send for ModuleLlvm {}-unsafe impl Sync for ModuleLlvm {}--impl ModuleLlvm {-    fn new(tcx: TyCtxt<'_>, mod_name: &str) -> Self {-        unsafe {-            let llcx = llvm::LLVMContextCreate();-            llvm::LLVMContextSetDiscardValueNames(llcx, tcx.sess.fewer_names().to_llvm_bool());-            let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;-            ModuleLlvm {-                llmod_raw,-                llcx,-                tm: ManuallyDrop::new(create_target_machine(tcx, mod_name)),-            }-        }-    }--    fn new_metadata(tcx: TyCtxt<'_>, mod_name: &str) -> Self {-        unsafe {-            let llcx = llvm::LLVMContextCreate();-            llvm::LLVMContextSetDiscardValueNames(llcx, tcx.sess.fewer_names().to_llvm_bool());-            let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;-            ModuleLlvm {-                llmod_raw,-                llcx,-                tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)),-            }-        }-    }--    fn parse(-        cgcx: &CodegenContext,-        tm_factory: TargetMachineFactoryFn<LlvmCodegenBackend>,-        name: &CStr,-        buffer: &[u8],-        dcx: DiagCtxtHandle<'_>,-    ) -> Self {-        unsafe {-            let llcx = llvm::LLVMContextCreate();-            llvm::LLVMContextSetDiscardValueNames(llcx, cgcx.fewer_names.to_llvm_bool());-            let llmod_raw = back::lto::parse_module(llcx, name, buffer, dcx);-            let tm = tm_factory(dcx, TargetMachineFactoryConfig::new(cgcx, name.to_str().unwrap()));--            ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) }-        }-    }--    fn llmod(&self) -> &llvm::Module {-        unsafe { &*self.llmod_raw }-    }-}--impl Drop for ModuleLlvm {-    fn drop(&mut self) {-        unsafe {-            ManuallyDrop::drop(&mut self.tm);-            llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));-        }-    }-}
compiler/rustc_codegen_llvm/src/llvm/ffi.rs2 + / 1
@@ -25,8 +25,9 @@ use super::debuginfo::{     DIArray, DIBuilder, DIDerivedType, DIDescriptor, DIFile, DIFlags, DILocation, DISPFlags,     DIScope, DISubprogram, DITemplateTypeParameter, DIType, DebugEmissionKind, DebugNameTableKind, };+use crate::llvm; use crate::llvm::MetadataKindId;-use crate::{TryFromU32, llvm};+use crate::macros::TryFromU32;  /// In the LLVM-C API, boolean values are passed as `typedef int LLVMBool`, /// which has a different ABI from Rust or C++ `bool`.