]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_llvm/src/lib.rs
Auto merge of #95519 - oli-obk:tait_ub2, r=compiler-errors
[rust.git] / compiler / rustc_codegen_llvm / src / lib.rs
1 //! The Rust compiler.
2 //!
3 //! # Note
4 //!
5 //! This API is completely unstable and subject to change.
6
7 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
8 #![feature(bool_to_option)]
9 #![feature(crate_visibility_modifier)]
10 #![feature(let_chains)]
11 #![feature(let_else)]
12 #![feature(extern_types)]
13 #![feature(once_cell)]
14 #![feature(nll)]
15 #![feature(iter_intersperse)]
16 #![recursion_limit = "256"]
17 #![allow(rustc::potential_query_instability)]
18
19 #[macro_use]
20 extern crate rustc_macros;
21
22 use back::write::{create_informational_target_machine, create_target_machine};
23
24 pub use llvm_util::target_features;
25 use rustc_ast::expand::allocator::AllocatorKind;
26 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
27 use rustc_codegen_ssa::back::write::{
28     CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn,
29 };
30 use rustc_codegen_ssa::traits::*;
31 use rustc_codegen_ssa::ModuleCodegen;
32 use rustc_codegen_ssa::{CodegenResults, CompiledModule};
33 use rustc_data_structures::fx::FxHashMap;
34 use rustc_errors::{ErrorGuaranteed, FatalError, Handler};
35 use rustc_metadata::EncodedMetadata;
36 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
37 use rustc_middle::ty::query::Providers;
38 use rustc_middle::ty::TyCtxt;
39 use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest};
40 use rustc_session::Session;
41 use rustc_span::symbol::Symbol;
42
43 use std::any::Any;
44 use std::ffi::CStr;
45
46 mod back {
47     pub mod archive;
48     pub mod lto;
49     mod profiling;
50     pub mod write;
51 }
52
53 mod abi;
54 mod allocator;
55 mod asm;
56 mod attributes;
57 mod base;
58 mod builder;
59 mod callee;
60 mod common;
61 mod consts;
62 mod context;
63 mod coverageinfo;
64 mod debuginfo;
65 mod declare;
66 mod intrinsic;
67
68 // The following is a work around that replaces `pub mod llvm;` and that fixes issue 53912.
69 #[path = "llvm/mod.rs"]
70 mod llvm_;
71 pub mod llvm {
72     pub use super::llvm_::*;
73 }
74
75 mod llvm_util;
76 mod mono_item;
77 mod type_;
78 mod type_of;
79 mod va_arg;
80 mod value;
81
82 #[derive(Clone)]
83 pub struct LlvmCodegenBackend(());
84
85 struct TimeTraceProfiler {
86     enabled: bool,
87 }
88
89 impl TimeTraceProfiler {
90     fn new(enabled: bool) -> Self {
91         if enabled {
92             unsafe { llvm::LLVMTimeTraceProfilerInitialize() }
93         }
94         TimeTraceProfiler { enabled }
95     }
96 }
97
98 impl Drop for TimeTraceProfiler {
99     fn drop(&mut self) {
100         if self.enabled {
101             unsafe { llvm::LLVMTimeTraceProfilerFinishThread() }
102         }
103     }
104 }
105
106 impl ExtraBackendMethods for LlvmCodegenBackend {
107     fn new_metadata(&self, tcx: TyCtxt<'_>, mod_name: &str) -> ModuleLlvm {
108         ModuleLlvm::new_metadata(tcx, mod_name)
109     }
110
111     fn codegen_allocator<'tcx>(
112         &self,
113         tcx: TyCtxt<'tcx>,
114         module_llvm: &mut ModuleLlvm,
115         module_name: &str,
116         kind: AllocatorKind,
117         has_alloc_error_handler: bool,
118     ) {
119         unsafe { allocator::codegen(tcx, module_llvm, module_name, kind, has_alloc_error_handler) }
120     }
121     fn compile_codegen_unit(
122         &self,
123         tcx: TyCtxt<'_>,
124         cgu_name: Symbol,
125     ) -> (ModuleCodegen<ModuleLlvm>, u64) {
126         base::compile_codegen_unit(tcx, cgu_name)
127     }
128     fn target_machine_factory(
129         &self,
130         sess: &Session,
131         optlvl: OptLevel,
132         target_features: &[String],
133     ) -> TargetMachineFactoryFn<Self> {
134         back::write::target_machine_factory(sess, optlvl, target_features)
135     }
136     fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str {
137         llvm_util::target_cpu(sess)
138     }
139     fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str> {
140         llvm_util::tune_cpu(sess)
141     }
142
143     fn spawn_thread<F, T>(time_trace: bool, f: F) -> std::thread::JoinHandle<T>
144     where
145         F: FnOnce() -> T,
146         F: Send + 'static,
147         T: Send + 'static,
148     {
149         std::thread::spawn(move || {
150             let _profiler = TimeTraceProfiler::new(time_trace);
151             f()
152         })
153     }
154
155     fn spawn_named_thread<F, T>(
156         time_trace: bool,
157         name: String,
158         f: F,
159     ) -> std::io::Result<std::thread::JoinHandle<T>>
160     where
161         F: FnOnce() -> T,
162         F: Send + 'static,
163         T: Send + 'static,
164     {
165         std::thread::Builder::new().name(name).spawn(move || {
166             let _profiler = TimeTraceProfiler::new(time_trace);
167             f()
168         })
169     }
170 }
171
172 impl WriteBackendMethods for LlvmCodegenBackend {
173     type Module = ModuleLlvm;
174     type ModuleBuffer = back::lto::ModuleBuffer;
175     type Context = llvm::Context;
176     type TargetMachine = &'static mut llvm::TargetMachine;
177     type ThinData = back::lto::ThinData;
178     type ThinBuffer = back::lto::ThinBuffer;
179     fn print_pass_timings(&self) {
180         unsafe {
181             llvm::LLVMRustPrintPassTimings();
182         }
183     }
184     fn run_link(
185         cgcx: &CodegenContext<Self>,
186         diag_handler: &Handler,
187         modules: Vec<ModuleCodegen<Self::Module>>,
188     ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
189         back::write::link(cgcx, diag_handler, modules)
190     }
191     fn run_fat_lto(
192         cgcx: &CodegenContext<Self>,
193         modules: Vec<FatLTOInput<Self>>,
194         cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
195     ) -> Result<LtoModuleCodegen<Self>, FatalError> {
196         back::lto::run_fat(cgcx, modules, cached_modules)
197     }
198     fn run_thin_lto(
199         cgcx: &CodegenContext<Self>,
200         modules: Vec<(String, Self::ThinBuffer)>,
201         cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
202     ) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
203         back::lto::run_thin(cgcx, modules, cached_modules)
204     }
205     unsafe fn optimize(
206         cgcx: &CodegenContext<Self>,
207         diag_handler: &Handler,
208         module: &ModuleCodegen<Self::Module>,
209         config: &ModuleConfig,
210     ) -> Result<(), FatalError> {
211         back::write::optimize(cgcx, diag_handler, module, config)
212     }
213     unsafe fn optimize_thin(
214         cgcx: &CodegenContext<Self>,
215         thin: &mut ThinModule<Self>,
216     ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
217         back::lto::optimize_thin_module(thin, cgcx)
218     }
219     unsafe fn codegen(
220         cgcx: &CodegenContext<Self>,
221         diag_handler: &Handler,
222         module: ModuleCodegen<Self::Module>,
223         config: &ModuleConfig,
224     ) -> Result<CompiledModule, FatalError> {
225         back::write::codegen(cgcx, diag_handler, module, config)
226     }
227     fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
228         back::lto::prepare_thin(module)
229     }
230     fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
231         (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))
232     }
233     fn run_lto_pass_manager(
234         cgcx: &CodegenContext<Self>,
235         module: &ModuleCodegen<Self::Module>,
236         config: &ModuleConfig,
237         thin: bool,
238     ) -> Result<(), FatalError> {
239         let diag_handler = cgcx.create_diag_handler();
240         back::lto::run_pass_manager(cgcx, &diag_handler, module, config, thin)
241     }
242 }
243
244 unsafe impl Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis
245 unsafe impl Sync for LlvmCodegenBackend {}
246
247 impl LlvmCodegenBackend {
248     pub fn new() -> Box<dyn CodegenBackend> {
249         Box::new(LlvmCodegenBackend(()))
250     }
251 }
252
253 impl CodegenBackend for LlvmCodegenBackend {
254     fn init(&self, sess: &Session) {
255         llvm_util::init(sess); // Make sure llvm is inited
256     }
257
258     fn provide(&self, providers: &mut Providers) {
259         providers.global_backend_features =
260             |tcx, ()| llvm_util::global_llvm_features(tcx.sess, true)
261     }
262
263     fn print(&self, req: PrintRequest, sess: &Session) {
264         match req {
265             PrintRequest::RelocationModels => {
266                 println!("Available relocation models:");
267                 for name in &[
268                     "static",
269                     "pic",
270                     "pie",
271                     "dynamic-no-pic",
272                     "ropi",
273                     "rwpi",
274                     "ropi-rwpi",
275                     "default",
276                 ] {
277                     println!("    {}", name);
278                 }
279                 println!();
280             }
281             PrintRequest::CodeModels => {
282                 println!("Available code models:");
283                 for name in &["tiny", "small", "kernel", "medium", "large"] {
284                     println!("    {}", name);
285                 }
286                 println!();
287             }
288             PrintRequest::TlsModels => {
289                 println!("Available TLS models:");
290                 for name in &["global-dynamic", "local-dynamic", "initial-exec", "local-exec"] {
291                     println!("    {}", name);
292                 }
293                 println!();
294             }
295             PrintRequest::StackProtectorStrategies => {
296                 println!(
297                     r#"Available stack protector strategies:
298     all
299         Generate stack canaries in all functions.
300
301     strong
302         Generate stack canaries in a function if it either:
303         - has a local variable of `[T; N]` type, regardless of `T` and `N`
304         - takes the address of a local variable.
305
306           (Note that a local variable being borrowed is not equivalent to its
307           address being taken: e.g. some borrows may be removed by optimization,
308           while by-value argument passing may be implemented with reference to a
309           local stack variable in the ABI.)
310
311     basic
312         Generate stack canaries in functions with:
313         - local variables of `[T; N]` type, where `T` is byte-sized and `N` > 8.
314
315     none
316         Do not generate stack canaries.
317 "#
318                 );
319             }
320             req => llvm_util::print(req, sess),
321         }
322     }
323
324     fn print_passes(&self) {
325         llvm_util::print_passes();
326     }
327
328     fn print_version(&self) {
329         llvm_util::print_version();
330     }
331
332     fn target_features(&self, sess: &Session) -> Vec<Symbol> {
333         target_features(sess)
334     }
335
336     fn codegen_crate<'tcx>(
337         &self,
338         tcx: TyCtxt<'tcx>,
339         metadata: EncodedMetadata,
340         need_metadata_module: bool,
341     ) -> Box<dyn Any> {
342         Box::new(rustc_codegen_ssa::base::codegen_crate(
343             LlvmCodegenBackend(()),
344             tcx,
345             crate::llvm_util::target_cpu(tcx.sess).to_string(),
346             metadata,
347             need_metadata_module,
348         ))
349     }
350
351     fn join_codegen(
352         &self,
353         ongoing_codegen: Box<dyn Any>,
354         sess: &Session,
355         outputs: &OutputFilenames,
356     ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorGuaranteed> {
357         let (codegen_results, work_products) = ongoing_codegen
358             .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
359             .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
360             .join(sess);
361
362         sess.time("llvm_dump_timing_file", || {
363             if sess.opts.debugging_opts.llvm_time_trace {
364                 let file_name = outputs.with_extension("llvm_timings.json");
365                 llvm_util::time_trace_profiler_finish(&file_name);
366             }
367         });
368
369         Ok((codegen_results, work_products))
370     }
371
372     fn link(
373         &self,
374         sess: &Session,
375         codegen_results: CodegenResults,
376         outputs: &OutputFilenames,
377     ) -> Result<(), ErrorGuaranteed> {
378         use crate::back::archive::LlvmArchiveBuilder;
379         use rustc_codegen_ssa::back::link::link_binary;
380
381         // Run the linker on any artifacts that resulted from the LLVM run.
382         // This should produce either a finished executable or library.
383         link_binary::<LlvmArchiveBuilder<'_>>(sess, &codegen_results, outputs)
384     }
385 }
386
387 pub struct ModuleLlvm {
388     llcx: &'static mut llvm::Context,
389     llmod_raw: *const llvm::Module,
390     tm: &'static mut llvm::TargetMachine,
391 }
392
393 unsafe impl Send for ModuleLlvm {}
394 unsafe impl Sync for ModuleLlvm {}
395
396 impl ModuleLlvm {
397     fn new(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
398         unsafe {
399             let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
400             let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
401             ModuleLlvm { llmod_raw, llcx, tm: create_target_machine(tcx, mod_name) }
402         }
403     }
404
405     fn new_metadata(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
406         unsafe {
407             let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
408             let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
409             ModuleLlvm { llmod_raw, llcx, tm: create_informational_target_machine(tcx.sess) }
410         }
411     }
412
413     fn parse(
414         cgcx: &CodegenContext<LlvmCodegenBackend>,
415         name: &CStr,
416         buffer: &[u8],
417         handler: &Handler,
418     ) -> Result<Self, FatalError> {
419         unsafe {
420             let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
421             let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?;
422             let tm_factory_config = TargetMachineFactoryConfig::new(cgcx, name.to_str().unwrap());
423             let tm = match (cgcx.tm_factory)(tm_factory_config) {
424                 Ok(m) => m,
425                 Err(e) => {
426                     handler.struct_err(&e).emit();
427                     return Err(FatalError);
428                 }
429             };
430
431             Ok(ModuleLlvm { llmod_raw, llcx, tm })
432         }
433     }
434
435     fn llmod(&self) -> &llvm::Module {
436         unsafe { &*self.llmod_raw }
437     }
438 }
439
440 impl Drop for ModuleLlvm {
441     fn drop(&mut self) {
442         unsafe {
443             llvm::LLVMRustDisposeTargetMachine(&mut *(self.tm as *mut _));
444             llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
445         }
446     }
447 }