1use std::any::Any;
5use std::ffi::CStr;
6use std::marker::PhantomData;
7use std::mem::ManuallyDrop;
8use std::path::PathBuf;
9use std::ptr;
10use std::sync::OnceLock;
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::{OptLevel, OutputFilenames, PrintKind, PrintRequest};
26use rustc_session::{
27 BorrowedIncrCompSession, CodegenBackendInit, EarlySession, IncrCompSession, Session,
28};
29use rustc_span::{Symbol, sym};
30use rustc_target::spec::{RelocModel, 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]
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(
93 &self,
94 sess: &Session,
95 optlvl: OptLevel,
96 ) -> TargetMachineFactoryFn<Self> {
97 back::write::target_machine_factory(sess, optlvl)
98 }
99 fn optimize_and_codegen_fat_lto(
100 sess: &Session,
101 cgcx: &CodegenContext,
102 shared_emitter: &SharedEmitter,
103 tm_factory: TargetMachineFactoryFn<LlvmCodegenBackend>,
104 exported_symbols_for_lto: &[String],
105 each_linked_rlib_for_lto: &[PathBuf],
106 modules: Vec<FatLtoInput<Self>>,
107 ) -> CompiledModule {
108 let mut module = back::lto::run_fat(
109 cgcx,
110 &sess.prof,
111 shared_emitter,
112 tm_factory,
113 exported_symbols_for_lto,
114 each_linked_rlib_for_lto,
115 modules,
116 );
117
118 let dcx = DiagCtxt::new(Box::new(shared_emitter.clone()));
119 let dcx = dcx.handle();
120 back::lto::run_pass_manager(cgcx, &sess.prof, dcx, &mut module, false);
121
122 back::write::codegen(cgcx, &sess.prof, shared_emitter, module, &cgcx.module_config)
123 }
124 fn run_thin_lto(
125 cgcx: &CodegenContext,
126 prof: &SelfProfilerRef,
127 incr_comp_session: Option<&BorrowedIncrCompSession>,
128 dcx: DiagCtxtHandle<'_>,
129 exported_symbols_for_lto: &[String],
130 each_linked_rlib_for_lto: &[PathBuf],
131 modules: Vec<ThinLtoInput<Self>>,
132 ) -> (Vec<ThinModule<Self>>, Vec<WorkProduct>) {
133 back::lto::run_thin(
134 cgcx,
135 prof,
136 incr_comp_session,
137 dcx,
138 exported_symbols_for_lto,
139 each_linked_rlib_for_lto,
140 modules,
141 )
142 }
143 fn optimize(
144 cgcx: &CodegenContext,
145 prof: &SelfProfilerRef,
146 shared_emitter: &SharedEmitter,
147 module: &mut ModuleCodegen<Self::Module>,
148 config: &ModuleConfig,
149 ) {
150 back::write::optimize(cgcx, prof, shared_emitter, module, config);
151 }
152 fn optimize_and_codegen_thin(
153 cgcx: &CodegenContext,
154 prof: &SelfProfilerRef,
155 shared_emitter: &SharedEmitter,
156 tm_factory: TargetMachineFactoryFn<LlvmCodegenBackend>,
157 thin: ThinModule<Self>,
158 ) -> CompiledModule {
159 back::lto::optimize_and_codegen_thin_module(cgcx, prof, shared_emitter, tm_factory, thin)
160 }
161 fn codegen(
162 cgcx: &CodegenContext,
163 prof: &SelfProfilerRef,
164 shared_emitter: &SharedEmitter,
165 module: ModuleCodegen<Self::Module>,
166 config: &ModuleConfig,
167 ) -> CompiledModule {
168 back::write::codegen(cgcx, prof, shared_emitter, module, config)
169 }
170 fn serialize_module(module: Self::Module, is_thin: bool) -> Self::ModuleBuffer {
171 module.with_module_refs(|ModuleRefs { llmod, .. }| {
172 back::lto::ModuleBuffer::new(llmod, is_thin)
173 })
174 }
175}
176
177impl LlvmCodegenBackend {
178 pub fn new() -> Box<dyn CodegenBackend> {
179 Box::new(LlvmCodegenBackend(()))
180 }
181}
182
183impl CodegenBackend for LlvmCodegenBackend {
184 fn name(&self) -> &'static str {
185 "llvm"
186 }
187
188 fn init(&mut self, sess: &EarlySession) -> CodegenBackendInit {
189 llvm_util::init(sess); let global_backend_features =
192 llvm_util::global_llvm_features(sess, false);
193
194 {
198 use rustc_session::config::AutoDiff;
199
200 use crate::back::lto::enable_autodiff_settings;
201 if sess.opts.unstable_opts.autodiff.contains(&AutoDiff::Enable) {
202 match llvm::EnzymeWrapper::get_or_init(&sess.opts.sysroot) {
203 Ok(_) => {}
204 Err(llvm::EnzymeLibraryError::NotFound { err }) => {
205 sess.dcx().emit_fatal(crate::diagnostics::AutoDiffComponentMissing { err });
206 }
207 Err(llvm::EnzymeLibraryError::LoadFailed { err }) => {
208 sess.dcx()
209 .emit_fatal(crate::diagnostics::AutoDiffComponentUnavailable { err });
210 }
211 }
212 enable_autodiff_settings(&sess.opts.unstable_opts.autodiff);
213 }
214 }
215
216 let replaced_intrinsics = {
218 #[rustfmt::skip]
219 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![
220 sym::unchecked_funnel_shl,
222 sym::unchecked_funnel_shr,
223 sym::carrying_mul_add,
224 sym::carryless_mul,
225 sym::integer_max,
226 sym::integer_min,
227
228 sym::sin,
230 sym::cos,
231 sym::powf,
232 sym::powi,
233 sym::sqrt,
234 sym::exp,
235 sym::exp2,
236 sym::log,
237 sym::log10,
238 sym::log2,
239 sym::floor, sym::ceil, sym::trunc,
240 sym::round, sym::round_ties_even,
241 sym::fma,
242
243 sym::copysignf16, sym::copysignf32, sym::copysignf64, sym::copysignf128,
244 ];
245
246 will_not_use_fallback
247 };
248
249 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];
255
256 CodegenBackendInit {
257 global_backend_features,
258 replaced_intrinsics,
259 fallback_intrinsics,
260 thin_lto_supported: true,
261 }
262 }
263
264 fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) {
265 use std::fmt::Write;
266 match req.kind {
267 PrintKind::RelocationModels => {
268 out.write_fmt(format_args!("Available relocation models:\n"))writeln!(out, "Available relocation models:").unwrap();
269 for name in RelocModel::ALL.iter().map(RelocModel::desc).chain(["default"]) {
270 out.write_fmt(format_args!(" {0}\n", name))writeln!(out, " {name}").unwrap();
271 }
272 out.write_fmt(format_args!("\n"))writeln!(out).unwrap();
273 }
274 PrintKind::CodeModels => {
275 out.write_fmt(format_args!("Available code models:\n"))writeln!(out, "Available code models:").unwrap();
276 for name in &["tiny", "small", "kernel", "medium", "large"] {
277 out.write_fmt(format_args!(" {0}\n", name))writeln!(out, " {name}").unwrap();
278 }
279 out.write_fmt(format_args!("\n"))writeln!(out).unwrap();
280 }
281 PrintKind::TlsModels => {
282 out.write_fmt(format_args!("Available TLS models:\n"))writeln!(out, "Available TLS models:").unwrap();
283 for name in TlsModel::ALL.iter().map(TlsModel::desc) {
284 out.write_fmt(format_args!(" {0}\n", name))writeln!(out, " {name}").unwrap();
285 }
286 out.write_fmt(format_args!("\n"))writeln!(out).unwrap();
287 }
288 PrintKind::StackProtectorStrategies => {
289 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!(
290 out,
291 r#"Available stack protector strategies:
292 all
293 Generate stack canaries in all functions.
294
295 strong
296 Generate stack canaries in a function if it either:
297 - has a local variable of `[T; N]` type, regardless of `T` and `N`
298 - takes the address of a local variable.
299
300 (Note that a local variable being borrowed is not equivalent to its
301 address being taken: e.g. some borrows may be removed by optimization,
302 while by-value argument passing may be implemented with reference to a
303 local stack variable in the ABI.)
304
305 basic
306 Generate stack canaries in functions with local variables of `[T; N]`
307 type, where `T` is byte-sized and `N` >= 8.
308
309 none
310 Do not generate stack canaries.
311"#
312 )
313 .unwrap();
314 }
315 _other => llvm_util::print(req, out, sess),
316 }
317 }
318
319 fn print_passes(&self) {
320 llvm_util::print_passes();
321 }
322
323 fn print_version(&self) {
324 llvm_util::print_version();
325 }
326
327 fn has_zstd(&self) -> bool {
328 llvm::LLVMRustLLVMHasZstdCompression()
329 }
330
331 fn has_mnemonic(&self, sess: &Session, mnemonic: &str) -> bool {
332 llvm_util::target_has_mnemonic(sess, mnemonic)
333 }
334
335 fn target_config(&self, sess: &EarlySession) -> TargetConfig {
336 target_config(sess)
337 }
338
339 fn target_cpu(&self, sess: &Session) -> String {
340 crate::llvm_util::target_cpu(sess).to_string()
341 }
342
343 fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box<dyn Any> {
344 use rustc_session::config::Offload;
345
346 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(_)))
347 || tcx.sess.opts.unstable_opts.offload.iter().any(|o| #[allow(non_exhaustive_omitted_patterns)] match o {
Offload::Host(_) => true,
_ => false,
}matches!(o, Offload::Host(_)))
348 {
349 match llvm::RustOffloadWrapper::get_or_init(&tcx.sess.opts.sysroot) {
350 Ok(_) => {}
351 Err(llvm::RustOffloadLibraryError::NotFound { err }) => {
352 tcx.sess
353 .dcx()
354 .emit_fatal(crate::diagnostics::RustOffloadComponentMissing { err });
355 }
356 Err(llvm::RustOffloadLibraryError::LoadFailed { err }) => {
357 tcx.sess
358 .dcx()
359 .emit_fatal(crate::diagnostics::RustOffloadComponentUnavailable { err });
360 }
361 }
362 }
363
364 Box::new(rustc_codegen_ssa::base::codegen_crate(LlvmCodegenBackend(()), tcx))
365 }
366
367 fn join_codegen(
368 &self,
369 ongoing_codegen: Box<dyn Any>,
370 sess: &Session,
371 incr_comp_session: Option<&IncrCompSession>,
372 outputs: &OutputFilenames,
373 crate_info: &CrateInfo,
374 ) -> (CompiledModules, WorkProductMap) {
375 let (compiled_modules, work_products) = ongoing_codegen
376 .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
377 .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
378 .join(sess, incr_comp_session, crate_info);
379
380 if sess.opts.unstable_opts.llvm_time_trace {
381 sess.time("llvm_dump_timing_file", || {
382 let file_name = outputs.with_extension("llvm_timings.json");
383 llvm_util::time_trace_profiler_finish(&file_name);
384 });
385 }
386
387 if sess.codegen_units().as_usize() == 1 && sess.opts.unstable_opts.time_llvm_passes {
388 let timings =
389 llvm::build_string(|s| unsafe { llvm::LLVMRustPrintPassTimings(s) }).unwrap();
390 { ::std::io::_print(format_args!("{0}", timings)); };print!("{timings}");
391 }
392
393 if sess.print_llvm_stats() {
394 let stats =
395 llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatistics(s) }).unwrap();
396 { ::std::io::_print(format_args!("{0}", stats)); };print!("{stats}");
397 }
398
399 if let Some(out_path) = sess.print_llvm_stats_json() {
400 let llvm_stats_json =
401 llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatisticsJSON(s) }).unwrap();
402
403 if !llvm_stats_json.is_empty() {
404 if let Err(e) = std::fs::write(&out_path, llvm_stats_json) {
405 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}"));
406 }
407 } else {
408 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!(
409 "requested to print LLVM statistics to JSON file {out_path}, but the codegen backend \
410 did not provide any statistics",
411 ));
412 }
413 }
414
415 (compiled_modules, work_products)
416 }
417
418 fn link(
419 &self,
420 sess: &Session,
421 compiled_modules: CompiledModules,
422 crate_info: CrateInfo,
423 metadata: EncodedMetadata,
424 outputs: &OutputFilenames,
425 ) {
426 use rustc_codegen_ssa::back::link::link_binary;
427
428 use crate::back::archive::LlvmArchiveBuilderBuilder;
429
430 link_binary(
433 sess,
434 &LlvmArchiveBuilderBuilder,
435 compiled_modules,
436 crate_info,
437 metadata,
438 outputs,
439 self.name(),
440 );
441 }
442}
443
444pub struct ModuleLlvm {
445 llcx_raw: ptr::NonNull<llvm::Context>,
446 llmod_raw: *const llvm::Module,
447
448 tm: ManuallyDrop<OwnedTargetMachine>,
451
452 pub(crate) thin_lto_buffer: OnceLock<Vec<u8>>,
457}
458
459unsafe impl Send for ModuleLlvm {}
460unsafe impl Sync for ModuleLlvm {}
461
462fn create_context_and_set_fewer_names(fewer_names: bool) -> ptr::NonNull<llvm::Context> {
465 unsafe {
466 let llcx_raw = llvm::LLVMContextCreate();
467 llvm::LLVMContextSetDiscardValueNames(llcx_raw.as_ref(), fewer_names.to_llvm_bool());
468 llcx_raw
469 }
470}
471
472impl ModuleLlvm {
473 pub(crate) fn new(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
474 unsafe {
475 let llcx_raw = create_context_and_set_fewer_names(tcx.sess.fewer_names());
476 let llmod_raw = context::create_module(tcx, llcx_raw.as_ref(), mod_name);
477 ModuleLlvm {
478 llmod_raw,
479 llcx_raw,
480 tm: ManuallyDrop::new(create_target_machine(tcx, mod_name)),
481 thin_lto_buffer: OnceLock::new(),
482 }
483 }
484 }
485
486 pub(crate) fn new_metadata(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
487 unsafe {
488 let llcx_raw = create_context_and_set_fewer_names(tcx.sess.fewer_names());
489 let llmod_raw = context::create_module(tcx, llcx_raw.as_ref(), mod_name);
490 ModuleLlvm {
491 llmod_raw,
492 llcx_raw,
493 tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)),
494 thin_lto_buffer: OnceLock::new(),
495 }
496 }
497 }
498
499 pub(crate) fn parse(
500 cgcx: &CodegenContext,
501 tm_factory: TargetMachineFactoryFn<LlvmCodegenBackend>,
502 name: &CStr,
503 buffer: &[u8],
504 dcx: DiagCtxtHandle<'_>,
505 ) -> Self {
506 unsafe {
507 let llcx_raw = create_context_and_set_fewer_names(cgcx.fewer_names);
508 let llmod_raw = back::lto::parse_module(llcx_raw.as_ref(), name, buffer, dcx);
509 let tm = tm_factory(dcx, TargetMachineFactoryConfig::new(cgcx, name.to_str().unwrap()));
510
511 ModuleLlvm {
512 llmod_raw,
513 llcx_raw,
514 tm: ManuallyDrop::new(tm),
515 thin_lto_buffer: OnceLock::new(),
516 }
517 }
518 }
519
520 pub(crate) fn with_module_refs<R>(
526 &self,
527 inner_fn: impl for<'ll> FnOnce(ModuleRefs<'ll>) -> R,
528 ) -> R {
529 inner_fn(ModuleRefs {
530 llcx: unsafe { self.llcx_raw.as_ref() },
531 llmod: unsafe { &*self.llmod_raw },
532 tm: self.tm.raw(),
533 _ph: PhantomData,
534 })
535 }
536}
537
538impl Drop for ModuleLlvm {
539 fn drop(&mut self) {
540 unsafe {
541 ManuallyDrop::drop(&mut self.tm);
542 llvm::LLVMContextDispose(self.llcx_raw);
543 }
544 }
545}
546
547#[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]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<&'ll llvm::Context>;
let _: ::core::clone::AssertParamIsClone<&'ll llvm::Module>;
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)]
549pub(crate) struct ModuleRefs<'ll> {
550 pub(crate) llcx: &'ll llvm::Context,
551 pub(crate) llmod: &'ll llvm::Module,
552 pub(crate) tm: &'ll llvm::TargetMachine,
553 _ph: PhantomData<fn(&'ll ()) -> &'ll ()>,
558}