Skip to main content

rustc_codegen_llvm/back/
llvm_backend.rs

1//! Module containing [`LlvmCodegenBackend`], which implements [`CodegenBackend`]
2//! and related traits for the LLVM codegen backend.
3
4use std::any::Any;
5use std::cell::OnceCell;
6use std::ffi::CStr;
7use std::marker::PhantomData;
8use std::mem::ManuallyDrop;
9use std::path::PathBuf;
10use std::ptr;
11
12use rustc_ast::expand::allocator::AllocatorMethod;
13use rustc_codegen_ssa::back::lto::ThinModule;
14use rustc_codegen_ssa::back::write::{
15    CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryConfig,
16    TargetMachineFactoryFn, ThinLtoInput,
17};
18use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, WriteBackendMethods};
19use rustc_codegen_ssa::{CompiledModule, CompiledModules, CrateInfo, ModuleCodegen, TargetConfig};
20use rustc_data_structures::profiling::SelfProfilerRef;
21use rustc_errors::{DiagCtxt, DiagCtxtHandle};
22use rustc_metadata::EncodedMetadata;
23use rustc_middle::dep_graph::{WorkProduct, WorkProductMap};
24use rustc_middle::ty::TyCtxt;
25use rustc_session::config::{LtoCli, OptLevel, OutputFilenames, PrintKind, PrintRequest};
26use rustc_session::{
27    BorrowedIncrCompSession, CodegenBackendInit, EarlySession, IncrCompSession, Session,
28};
29use rustc_span::{Symbol, sym};
30use rustc_target::spec::{RelocModel, SplitDebuginfo, TlsModel};
31
32use crate::back::owned_target_machine::OwnedTargetMachine;
33use crate::back::write::{create_informational_target_machine, create_target_machine};
34use crate::context::{self, SimpleCx};
35use crate::llvm::{self, ToLlvmBool};
36use crate::llvm_util::{self, target_config};
37use crate::{allocator, back, base};
38
39#[derive(#[automatically_derived]impl ::core::clone::Clone for LlvmCodegenBackend {
    #[inline]
    #[rustc_trivial_field_reads]
    fn clone(&self) -> Self {
        LlvmCodegenBackend(::core::clone::Clone::clone(&self.0))
    }
}Clone)]
40pub struct LlvmCodegenBackend(());
41
42struct TimeTraceProfiler {}
43
44impl TimeTraceProfiler {
45    fn new() -> Self {
46        unsafe { llvm::LLVMRustTimeTraceProfilerInitialize() }
47        TimeTraceProfiler {}
48    }
49}
50
51impl Drop for TimeTraceProfiler {
52    fn drop(&mut self) {
53        unsafe { llvm::LLVMRustTimeTraceProfilerFinishThread() }
54    }
55}
56
57impl ExtraBackendMethods for LlvmCodegenBackend {
58    type Module = ModuleLlvm;
59
60    fn codegen_allocator<'tcx>(
61        &self,
62        tcx: TyCtxt<'tcx>,
63        module_name: &str,
64        methods: &[AllocatorMethod],
65    ) -> ModuleLlvm {
66        let module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
67        module_llvm.with_module_refs(|ModuleRefs { llcx, llmod, .. }| {
68            let cx = SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size());
69            unsafe { allocator::codegen(tcx, cx, module_name, methods) };
70        });
71        module_llvm
72    }
73    fn compile_codegen_unit(
74        &self,
75        tcx: TyCtxt<'_>,
76        cgu_name: Symbol,
77        bitcode_needed: bool,
78    ) -> (ModuleCodegen<ModuleLlvm>, u64) {
79        base::compile_codegen_unit(tcx, cgu_name, bitcode_needed)
80    }
81}
82
83impl WriteBackendMethods for LlvmCodegenBackend {
84    type Module = ModuleLlvm;
85    type ModuleBuffer = back::lto::ModuleBuffer;
86    type TargetMachine = OwnedTargetMachine;
87    type ThinData = back::lto::ThinData;
88
89    fn thread_profiler() -> Box<dyn Any> {
90        Box::new(TimeTraceProfiler::new())
91    }
92    fn target_machine_factory(&self, sess: &Session) -> TargetMachineFactoryFn<Self> {
93        back::write::target_machine_factory(sess, sess.opts.optimize)
94    }
95    fn optimize_and_codegen_fat_lto(
96        sess: &Session,
97        cgcx: &CodegenContext,
98        shared_emitter: &SharedEmitter,
99        tm_factory: TargetMachineFactoryFn<LlvmCodegenBackend>,
100        exported_symbols_for_lto: &[String],
101        each_linked_rlib_for_lto: &[PathBuf],
102        modules: Vec<FatLtoInput<Self>>,
103    ) -> CompiledModule {
104        let module = back::lto::run_fat(
105            cgcx,
106            &sess.prof,
107            shared_emitter,
108            tm_factory,
109            exported_symbols_for_lto,
110            each_linked_rlib_for_lto,
111            modules,
112        );
113
114        let dcx = DiagCtxt::new(Box::new(shared_emitter.clone()));
115        let dcx = dcx.handle();
116        back::lto::run_pass_manager(cgcx, &sess.prof, dcx, &module, false);
117
118        back::write::codegen(cgcx, &sess.prof, shared_emitter, module, &cgcx.module_config)
119    }
120    fn run_thin_lto(
121        cgcx: &CodegenContext,
122        prof: &SelfProfilerRef,
123        incr_comp_session: Option<&BorrowedIncrCompSession>,
124        dcx: DiagCtxtHandle<'_>,
125        exported_symbols_for_lto: &[String],
126        each_linked_rlib_for_lto: &[PathBuf],
127        modules: Vec<ThinLtoInput<Self>>,
128    ) -> (Vec<ThinModule<Self>>, Vec<WorkProduct>) {
129        back::lto::run_thin(
130            cgcx,
131            prof,
132            incr_comp_session,
133            dcx,
134            exported_symbols_for_lto,
135            each_linked_rlib_for_lto,
136            modules,
137        )
138    }
139    fn optimize(
140        cgcx: &CodegenContext,
141        prof: &SelfProfilerRef,
142        shared_emitter: &SharedEmitter,
143        module: &mut ModuleCodegen<Self::Module>,
144        config: &ModuleConfig,
145    ) {
146        back::write::optimize(cgcx, prof, shared_emitter, module, config);
147    }
148    fn optimize_and_codegen_thin(
149        cgcx: &CodegenContext,
150        prof: &SelfProfilerRef,
151        shared_emitter: &SharedEmitter,
152        tm_factory: TargetMachineFactoryFn<LlvmCodegenBackend>,
153        thin: ThinModule<Self>,
154    ) -> CompiledModule {
155        back::lto::optimize_and_codegen_thin_module(cgcx, prof, shared_emitter, tm_factory, thin)
156    }
157    fn codegen(
158        cgcx: &CodegenContext,
159        prof: &SelfProfilerRef,
160        shared_emitter: &SharedEmitter,
161        module: ModuleCodegen<Self::Module>,
162        config: &ModuleConfig,
163    ) -> CompiledModule {
164        back::write::codegen(cgcx, prof, shared_emitter, module, config)
165    }
166    fn serialize_module(module: Self::Module, is_thin: bool) -> Self::ModuleBuffer {
167        module.with_module_refs(|ModuleRefs { llmod, .. }| {
168            back::lto::ModuleBuffer::new(llmod, is_thin)
169        })
170    }
171}
172
173impl LlvmCodegenBackend {
174    pub fn new() -> Box<dyn CodegenBackend> {
175        Box::new(LlvmCodegenBackend(()))
176    }
177}
178
179impl CodegenBackend for LlvmCodegenBackend {
180    fn name(&self) -> &'static str {
181        "llvm"
182    }
183
184    fn init(&mut self, sess: &EarlySession) -> CodegenBackendInit {
185        llvm_util::init(sess); // Make sure llvm is inited
186
187        let global_backend_features =
188            llvm_util::global_llvm_features(sess, /* for_cfg */ false);
189
190        // autodiff is based on Enzyme, a library which we might not have available, when it was
191        // neither build, nor downloaded via rustup. If autodiff is used, but not available we emit
192        // an early error here and abort compilation.
193        {
194            use rustc_session::config::AutoDiff;
195
196            use crate::back::lto::enable_autodiff_settings;
197            if sess.opts.unstable_opts.autodiff.contains(&AutoDiff::Enable) {
198                match llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) {
199                    Ok(_) => {}
200                    Err(llvm::EnzymeLibraryError::NotFound { err }) => {
201                        sess.dcx().emit_fatal(crate::diagnostics::AutoDiffComponentMissing { err });
202                    }
203                    Err(llvm::EnzymeLibraryError::LoadFailed { err }) => {
204                        sess.dcx()
205                            .emit_fatal(crate::diagnostics::AutoDiffComponentUnavailable { err });
206                    }
207                }
208                enable_autodiff_settings(&sess.opts.unstable_opts.autodiff);
209            }
210        }
211
212        // -Zllvm-tpde requires the TPDE pass plugin, which may not be available. If TPDE is used but not available,
213        // we emit an early error here and abort compilation.
214        {
215            match llvm::TpdeWrapper::get_or_init(
216                &sess.opts.sysroot,
217                &sess.opts.unstable_opts.llvm_tpde,
218            ) {
219                Ok(_) => {}
220                Err(llvm::TpdeLibraryError::NotFound { err }) => {
221                    sess.dcx().emit_fatal(crate::diagnostics::TpdeComponentMissing { err });
222                }
223                Err(llvm::TpdeLibraryError::LoadFailed { err }) => {
224                    sess.dcx().emit_fatal(crate::diagnostics::TpdeComponentUnavailable { err });
225                }
226            }
227
228            if sess.opts.unstable_opts.llvm_tpde.is_some() {
229                if !#[allow(non_exhaustive_omitted_patterns)] match sess.opts.optimize {
    OptLevel::No | OptLevel::Less => true,
    _ => false,
}matches!(sess.opts.optimize, OptLevel::No | OptLevel::Less) {
230                    sess.dcx().emit_warn(crate::diagnostics::TpdeHighOptLevel);
231                }
232
233                if sess.target.requires_lto
234                    || !#[allow(non_exhaustive_omitted_patterns)] match sess.early_lto() {
    LtoCli::No | LtoCli::Unspecified => true,
    _ => false,
}matches!(sess.early_lto(), LtoCli::No | LtoCli::Unspecified)
235                {
236                    sess.dcx().emit_fatal(crate::diagnostics::TpdeLtoUsed);
237                }
238
239                // JUSTIFICATION: the session doesn't exist at this point.
240                #[allow(rustc::bad_opt_access)]
241                if sess.opts.cg.split_debuginfo.unwrap_or(sess.target.split_debuginfo)
242                    != SplitDebuginfo::Off
243                {
244                    sess.dcx().emit_fatal(crate::diagnostics::TpdeSplitDebugInfoUsed);
245                }
246            }
247        }
248
249        // Intrinsics whose fallback body will not be used by the LLVM backend.
250        let replaced_intrinsics = {
251            #[rustfmt::skip]
252            let will_not_use_fallback = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [sym::unchecked_funnel_shl, sym::unchecked_funnel_shr,
                sym::carrying_mul_add, sym::carryless_mul, sym::integer_max,
                sym::integer_min, sym::sin, sym::cos, sym::powf, sym::powi,
                sym::sqrt, sym::exp, sym::exp2, sym::log, sym::log10,
                sym::log2, sym::floor, sym::ceil, sym::trunc, sym::round,
                sym::round_ties_even, sym::fma, sym::copysignf16,
                sym::copysignf32, sym::copysignf64, sym::copysignf128]))vec![
253                // These are mapped to LLVM intrinsics instead.
254                sym::unchecked_funnel_shl,
255                sym::unchecked_funnel_shr,
256                sym::carrying_mul_add,
257                sym::carryless_mul,
258                sym::integer_max,
259                sym::integer_min,
260
261                // Fallback via libm/compiler-builtins, but the LLVM intrinsic is used instead.
262                sym::sin,
263                sym::cos,
264                sym::powf,
265                sym::powi,
266                sym::sqrt,
267                sym::exp,
268                sym::exp2,
269                sym::log,
270                sym::log10,
271                sym::log2,
272                sym::floor, sym::ceil, sym::trunc,
273                sym::round, sym::round_ties_even,
274                sym::fma,
275
276                sym::copysignf16, sym::copysignf32, sym::copysignf64, sym::copysignf128,
277            ];
278
279            will_not_use_fallback
280        };
281
282        // `type_id_eq` is a safe choice since *all* backends use the fallback body for that. When
283        // adding more intrinsics, keep in mind that the distributed standard library is compiled
284        // with the LLVM backend but might later be included in a project built with cranelift or
285        // GCC. Adding an intrinsic here can therefore mean the fallback body is used with
286        // cranelift/GCC even if they have dedicated implementations.
287        let fallback_intrinsics = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [sym::type_id_eq]))vec![sym::type_id_eq];
288
289        CodegenBackendInit {
290            global_backend_features,
291            replaced_intrinsics,
292            fallback_intrinsics,
293            thin_lto_supported: true,
294        }
295    }
296
297    fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) {
298        use std::fmt::Write;
299        match req.kind {
300            PrintKind::RelocationModels => {
301                out.write_fmt(format_args!("Available relocation models:\n"))writeln!(out, "Available relocation models:").unwrap();
302                for name in RelocModel::ALL.iter().map(RelocModel::desc).chain(["default"]) {
303                    out.write_fmt(format_args!("    {0}\n", name))writeln!(out, "    {name}").unwrap();
304                }
305                out.write_fmt(format_args!("\n"))writeln!(out).unwrap();
306            }
307            PrintKind::CodeModels => {
308                out.write_fmt(format_args!("Available code models:\n"))writeln!(out, "Available code models:").unwrap();
309                for name in &["tiny", "small", "kernel", "medium", "large"] {
310                    out.write_fmt(format_args!("    {0}\n", name))writeln!(out, "    {name}").unwrap();
311                }
312                out.write_fmt(format_args!("\n"))writeln!(out).unwrap();
313            }
314            PrintKind::TlsModels => {
315                out.write_fmt(format_args!("Available TLS models:\n"))writeln!(out, "Available TLS models:").unwrap();
316                for name in TlsModel::ALL.iter().map(TlsModel::desc) {
317                    out.write_fmt(format_args!("    {0}\n", name))writeln!(out, "    {name}").unwrap();
318                }
319                out.write_fmt(format_args!("\n"))writeln!(out).unwrap();
320            }
321            PrintKind::StackProtectorStrategies => {
322                out.write_fmt(format_args!("Available stack protector strategies:\n    all\n        Generate stack canaries in all functions.\n\n    strong\n        Generate stack canaries in a function if it either:\n        - has a local variable of `[T; N]` type, regardless of `T` and `N`\n        - takes the address of a local variable.\n\n          (Note that a local variable being borrowed is not equivalent to its\n          address being taken: e.g. some borrows may be removed by optimization,\n          while by-value argument passing may be implemented with reference to a\n          local stack variable in the ABI.)\n\n    basic\n        Generate stack canaries in functions with local variables of `[T; N]`\n        type, where `T` is byte-sized and `N` >= 8.\n\n    none\n        Do not generate stack canaries.\n\n"))writeln!(
323                    out,
324                    r#"Available stack protector strategies:
325    all
326        Generate stack canaries in all functions.
327
328    strong
329        Generate stack canaries in a function if it either:
330        - has a local variable of `[T; N]` type, regardless of `T` and `N`
331        - takes the address of a local variable.
332
333          (Note that a local variable being borrowed is not equivalent to its
334          address being taken: e.g. some borrows may be removed by optimization,
335          while by-value argument passing may be implemented with reference to a
336          local stack variable in the ABI.)
337
338    basic
339        Generate stack canaries in functions with local variables of `[T; N]`
340        type, where `T` is byte-sized and `N` >= 8.
341
342    none
343        Do not generate stack canaries.
344"#
345                )
346                .unwrap();
347            }
348            _other => llvm_util::print(req, out, sess),
349        }
350    }
351
352    fn print_passes(&self) {
353        llvm_util::print_passes();
354    }
355
356    fn print_version(&self) {
357        llvm_util::print_version();
358    }
359
360    fn has_zstd(&self) -> bool {
361        llvm::LLVMRustLLVMHasZstdCompression()
362    }
363
364    fn has_mnemonic(&self, sess: &Session, mnemonic: &str) -> bool {
365        llvm_util::target_has_mnemonic(sess, mnemonic)
366    }
367
368    fn target_config(&self, sess: &EarlySession) -> TargetConfig {
369        target_config(sess)
370    }
371
372    fn target_cpu(&self, sess: &Session) -> String {
373        crate::llvm_util::target_cpu(sess).to_string()
374    }
375
376    fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box<dyn Any> {
377        use rustc_session::config::Offload;
378
379        if tcx.sess.opts.unstable_opts.offload.iter().any(|o| #[allow(non_exhaustive_omitted_patterns)] match o {
    Offload::Device(_) => true,
    _ => false,
}matches!(o, Offload::Device(_)))
380            || tcx.sess.opts.unstable_opts.offload.iter().any(|o| #[allow(non_exhaustive_omitted_patterns)] match o {
    Offload::Host(_) => true,
    _ => false,
}matches!(o, Offload::Host(_)))
381        {
382            match llvm::RustOffloadWrapper::get_or_init(&tcx.sess.opts.sysroot) {
383                Ok(_) => {}
384                Err(llvm::RustOffloadLibraryError::NotFound { err }) => {
385                    tcx.sess
386                        .dcx()
387                        .emit_fatal(crate::diagnostics::RustOffloadComponentMissing { err });
388                }
389                Err(llvm::RustOffloadLibraryError::LoadFailed { err }) => {
390                    tcx.sess
391                        .dcx()
392                        .emit_fatal(crate::diagnostics::RustOffloadComponentUnavailable { err });
393                }
394            }
395        }
396
397        Box::new(rustc_codegen_ssa::base::codegen_crate(LlvmCodegenBackend(()), tcx))
398    }
399
400    fn join_codegen(
401        &self,
402        ongoing_codegen: Box<dyn Any>,
403        sess: &Session,
404        incr_comp_session: Option<&IncrCompSession>,
405        outputs: &OutputFilenames,
406        crate_info: &CrateInfo,
407    ) -> (CompiledModules, WorkProductMap) {
408        let (compiled_modules, work_products) = ongoing_codegen
409            .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
410            .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
411            .join(sess, incr_comp_session, crate_info);
412
413        if sess.opts.unstable_opts.llvm_time_trace {
414            sess.time("llvm_dump_timing_file", || {
415                let file_name = outputs.with_extension("llvm_timings.json");
416                llvm_util::time_trace_profiler_finish(&file_name);
417            });
418        }
419
420        if sess.codegen_units().as_usize() == 1 && sess.opts.unstable_opts.time_llvm_passes {
421            let timings =
422                llvm::build_string(|s| unsafe { llvm::LLVMRustPrintPassTimings(s) }).unwrap();
423            { ::std::io::_print(format_args!("{0}", timings)); };print!("{timings}");
424        }
425
426        if sess.print_llvm_stats() {
427            let stats =
428                llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatistics(s) }).unwrap();
429            { ::std::io::_print(format_args!("{0}", stats)); };print!("{stats}");
430        }
431
432        if let Some(out_path) = sess.print_llvm_stats_json() {
433            let llvm_stats_json =
434                llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatisticsJSON(s) }).unwrap();
435
436            if !llvm_stats_json.is_empty() {
437                if let Err(e) = std::fs::write(out_path, llvm_stats_json) {
438                    sess.dcx().err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("failed to write stats to {0}: {1}",
                out_path, e))
    })format!("failed to write stats to {out_path}: {e}"));
439                }
440            } else {
441                sess.dcx().warn(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("requested to print LLVM statistics to JSON file {0}, but the codegen backend did not provide any statistics",
                out_path))
    })format!(
442                    "requested to print LLVM statistics to JSON file {out_path}, but the codegen backend \
443                    did not provide any statistics",
444                ));
445            }
446        }
447
448        (compiled_modules, work_products)
449    }
450
451    fn link(
452        &self,
453        sess: &Session,
454        compiled_modules: CompiledModules,
455        crate_info: CrateInfo,
456        metadata: EncodedMetadata,
457        outputs: &OutputFilenames,
458    ) {
459        use rustc_codegen_ssa::back::link::link_binary;
460
461        use crate::back::archive::LlvmArchiveBuilderBuilder;
462
463        // Run the linker on any artifacts that resulted from the LLVM run.
464        // This should produce either a finished executable or library.
465        link_binary(
466            sess,
467            &LlvmArchiveBuilderBuilder,
468            compiled_modules,
469            crate_info,
470            metadata,
471            outputs,
472            self.name(),
473        );
474    }
475}
476
477pub struct ModuleLlvm {
478    llcx_raw: ptr::NonNull<llvm::ContextRaw>,
479    llmod_raw: ptr::NonNull<llvm::ModuleRaw>,
480
481    // This field is `ManuallyDrop` because it is important that the `TargetMachine`
482    // is disposed prior to the `Context` being disposed otherwise UAFs can occur.
483    tm: ManuallyDrop<OwnedTargetMachine>,
484
485    /// Saved ThinLTO buffer for embedding in the object file.
486    ///
487    /// This is currently a `OnceCell` to avoid aliasing problems when writing to it
488    /// from code that also wants to pass around a shared ref to `ModuleCodegen`.
489    pub(crate) thin_lto_buffer: OnceCell<Vec<u8>>,
490}
491
492// An LLVM context can only be used by one thread at a time. But we can move the entire context and
493// all objects inside it to another thread (needed for parallel codegen). This is sound because
494// `ModuleLlvm` owns the context and only allows borrowing LLVM objects tied to the context.
495unsafe impl Send for ModuleLlvm {}
496
497/// Shared helper to call [`llvm::LLVMContextCreate`] and then configure
498/// [`llvm::LLVMContextSetDiscardValueNames`].
499fn create_context_and_set_fewer_names(fewer_names: bool) -> ptr::NonNull<llvm::ContextRaw> {
500    unsafe {
501        let llcx_raw = llvm::LLVMContextCreate();
502        llvm::LLVMContextSetDiscardValueNames(
503            llvm::wrap_llcx(llcx_raw),
504            fewer_names.to_llvm_bool(),
505        );
506        llcx_raw
507    }
508}
509
510impl ModuleLlvm {
511    pub(crate) fn new(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
512        unsafe {
513            let llcx_raw = create_context_and_set_fewer_names(tcx.sess.fewer_names());
514            let llmod_raw =
515                context::create_module(tcx, llvm::wrap_llcx(llcx_raw), mod_name).llmod_raw();
516            ModuleLlvm {
517                llmod_raw,
518                llcx_raw,
519                tm: ManuallyDrop::new(create_target_machine(tcx, mod_name)),
520                thin_lto_buffer: OnceCell::new(),
521            }
522        }
523    }
524
525    pub(crate) fn new_metadata(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
526        unsafe {
527            let llcx_raw = create_context_and_set_fewer_names(tcx.sess.fewer_names());
528            let llmod_raw =
529                context::create_module(tcx, llvm::wrap_llcx(llcx_raw), mod_name).llmod_raw();
530            ModuleLlvm {
531                llmod_raw,
532                llcx_raw,
533                tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)),
534                thin_lto_buffer: OnceCell::new(),
535            }
536        }
537    }
538
539    pub(crate) fn parse(
540        cgcx: &CodegenContext,
541        tm_factory: TargetMachineFactoryFn<LlvmCodegenBackend>,
542        name: &CStr,
543        buffer: &[u8],
544        dcx: DiagCtxtHandle<'_>,
545    ) -> Self {
546        unsafe {
547            let llcx_raw = create_context_and_set_fewer_names(cgcx.fewer_names);
548            let llmod_raw =
549                back::lto::parse_module(llvm::wrap_llcx(llcx_raw), name, buffer, dcx).llmod_raw();
550            let tm = tm_factory(dcx, TargetMachineFactoryConfig::new(cgcx, name.to_str().unwrap()));
551
552            ModuleLlvm {
553                llmod_raw,
554                llcx_raw,
555                tm: ManuallyDrop::new(tm),
556                thin_lto_buffer: OnceCell::new(),
557            }
558        }
559    }
560
561    /// Passes a [`ModuleRefs`] struct to a callback function, giving it scoped
562    /// access to the resources owned by this module.
563    ///
564    /// Passing the references to a callback ensures that they have coherent
565    /// `'ll` lifetimes, and that they can't escape the callback.
566    pub(crate) fn with_module_refs<R>(
567        &self,
568        inner_fn: impl for<'ll> FnOnce(ModuleRefs<'ll>) -> R,
569    ) -> R {
570        let llcx = unsafe { llvm::wrap_llcx(self.llcx_raw) };
571        let llmod = unsafe { llvm::wrap_llmod(llcx, self.llmod_raw) };
572        inner_fn(ModuleRefs { llcx, llmod, tm: self.tm.raw(), _ph: PhantomData })
573    }
574}
575
576impl Drop for ModuleLlvm {
577    fn drop(&mut self) {
578        unsafe {
579            ManuallyDrop::drop(&mut self.tm);
580            llvm::LLVMContextDispose(self.llcx_raw);
581        }
582    }
583}
584
585/// Bundle of references provided by [`ModuleLlvm::with_module_refs`].
586#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl<'ll>
    ::core::clone::TrivialClone for ModuleRefs<'ll> {
}
#[automatically_derived]impl<'ll> ::core::clone::Clone for ModuleRefs<'ll> {
    #[inline]
    #[rustc_trivial_field_reads]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<llvm::Context<'ll>>;
        let _: ::core::clone::AssertParamIsClone<llvm::Module<'ll>>;
        let _: ::core::clone::AssertParamIsClone<&'ll llvm::TargetMachine>;
        let _:
                ::core::clone::AssertParamIsClone<PhantomData<fn(&'ll ())
                    -> &'ll ()>>;
        *self
    }
}Clone, #[automatically_derived]impl<'ll> ::core::marker::Copy for ModuleRefs<'ll> { }Copy)]
587pub(crate) struct ModuleRefs<'ll> {
588    pub(crate) llcx: llvm::Context<'ll>,
589    pub(crate) llmod: llvm::Module<'ll>,
590    pub(crate) tm: &'ll llvm::TargetMachine,
591    /// Make sure `'ll` is invariant, even if no fields happen to require that.
592    ///
593    /// FIXME(Zalathar): Consider using `PhantomInvariantLifetime` when the API
594    /// for that is settled.
595    _ph: PhantomData<fn(&'ll ()) -> &'ll ()>,
596}