]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_llvm/lib.rs
Auto merge of #73046 - marmeladema:save-analysis-fix-path, r=Xanewok
[rust.git] / src / librustc_codegen_llvm / 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/")]
8 #![feature(bool_to_option)]
9 #![feature(const_cstr_unchecked)]
10 #![feature(crate_visibility_modifier)]
11 #![feature(extern_types)]
12 #![feature(in_band_lifetimes)]
13 #![feature(nll)]
14 #![feature(or_patterns)]
15 #![feature(trusted_len)]
16 #![recursion_limit = "256"]
17
18 use back::write::{create_informational_target_machine, create_target_machine};
19
20 pub use llvm_util::target_features;
21 use rustc_ast::expand::allocator::AllocatorKind;
22 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
23 use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig};
24 use rustc_codegen_ssa::traits::*;
25 use rustc_codegen_ssa::ModuleCodegen;
26 use rustc_codegen_ssa::{CodegenResults, CompiledModule};
27 use rustc_errors::{ErrorReported, FatalError, Handler};
28 use rustc_middle::dep_graph::{DepGraph, WorkProduct};
29 use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn};
30 use rustc_middle::ty::{self, TyCtxt};
31 use rustc_serialize::json;
32 use rustc_session::config::{self, OptLevel, OutputFilenames, PrintRequest};
33 use rustc_session::Session;
34 use rustc_span::symbol::Symbol;
35
36 use std::any::Any;
37 use std::ffi::CStr;
38 use std::fs;
39 use std::sync::Arc;
40
41 mod back {
42     pub mod archive;
43     pub mod lto;
44     mod profiling;
45     pub mod write;
46 }
47
48 mod abi;
49 mod allocator;
50 mod asm;
51 mod attributes;
52 mod base;
53 mod builder;
54 mod callee;
55 mod common;
56 mod consts;
57 mod context;
58 mod debuginfo;
59 mod declare;
60 mod intrinsic;
61
62 // The following is a work around that replaces `pub mod llvm;` and that fixes issue 53912.
63 #[path = "llvm/mod.rs"]
64 mod llvm_;
65 pub mod llvm {
66     pub use super::llvm_::*;
67 }
68
69 mod llvm_util;
70 mod metadata;
71 mod mono_item;
72 mod type_;
73 mod type_of;
74 mod va_arg;
75 mod value;
76
77 #[derive(Clone)]
78 pub struct LlvmCodegenBackend(());
79
80 impl ExtraBackendMethods for LlvmCodegenBackend {
81     fn new_metadata(&self, tcx: TyCtxt<'_>, mod_name: &str) -> ModuleLlvm {
82         ModuleLlvm::new_metadata(tcx, mod_name)
83     }
84
85     fn write_compressed_metadata<'tcx>(
86         &self,
87         tcx: TyCtxt<'tcx>,
88         metadata: &EncodedMetadata,
89         llvm_module: &mut ModuleLlvm,
90     ) {
91         base::write_compressed_metadata(tcx, metadata, llvm_module)
92     }
93     fn codegen_allocator<'tcx>(
94         &self,
95         tcx: TyCtxt<'tcx>,
96         mods: &mut ModuleLlvm,
97         kind: AllocatorKind,
98     ) {
99         unsafe { allocator::codegen(tcx, mods, kind) }
100     }
101     fn compile_codegen_unit(
102         &self,
103         tcx: TyCtxt<'_>,
104         cgu_name: Symbol,
105     ) -> (ModuleCodegen<ModuleLlvm>, u64) {
106         base::compile_codegen_unit(tcx, cgu_name)
107     }
108     fn target_machine_factory(
109         &self,
110         sess: &Session,
111         optlvl: OptLevel,
112     ) -> Arc<dyn Fn() -> Result<&'static mut llvm::TargetMachine, String> + Send + Sync> {
113         back::write::target_machine_factory(sess, optlvl)
114     }
115     fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str {
116         llvm_util::target_cpu(sess)
117     }
118 }
119
120 impl WriteBackendMethods for LlvmCodegenBackend {
121     type Module = ModuleLlvm;
122     type ModuleBuffer = back::lto::ModuleBuffer;
123     type Context = llvm::Context;
124     type TargetMachine = &'static mut llvm::TargetMachine;
125     type ThinData = back::lto::ThinData;
126     type ThinBuffer = back::lto::ThinBuffer;
127     fn print_pass_timings(&self) {
128         unsafe {
129             llvm::LLVMRustPrintPassTimings();
130         }
131     }
132     fn run_fat_lto(
133         cgcx: &CodegenContext<Self>,
134         modules: Vec<FatLTOInput<Self>>,
135         cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
136     ) -> Result<LtoModuleCodegen<Self>, FatalError> {
137         back::lto::run_fat(cgcx, modules, cached_modules)
138     }
139     fn run_thin_lto(
140         cgcx: &CodegenContext<Self>,
141         modules: Vec<(String, Self::ThinBuffer)>,
142         cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
143     ) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
144         back::lto::run_thin(cgcx, modules, cached_modules)
145     }
146     unsafe fn optimize(
147         cgcx: &CodegenContext<Self>,
148         diag_handler: &Handler,
149         module: &ModuleCodegen<Self::Module>,
150         config: &ModuleConfig,
151     ) -> Result<(), FatalError> {
152         back::write::optimize(cgcx, diag_handler, module, config)
153     }
154     unsafe fn optimize_thin(
155         cgcx: &CodegenContext<Self>,
156         thin: &mut ThinModule<Self>,
157     ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
158         back::lto::optimize_thin_module(thin, cgcx)
159     }
160     unsafe fn codegen(
161         cgcx: &CodegenContext<Self>,
162         diag_handler: &Handler,
163         module: ModuleCodegen<Self::Module>,
164         config: &ModuleConfig,
165     ) -> Result<CompiledModule, FatalError> {
166         back::write::codegen(cgcx, diag_handler, module, config)
167     }
168     fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
169         back::lto::prepare_thin(module)
170     }
171     fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
172         (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))
173     }
174     fn run_lto_pass_manager(
175         cgcx: &CodegenContext<Self>,
176         module: &ModuleCodegen<Self::Module>,
177         config: &ModuleConfig,
178         thin: bool,
179     ) {
180         back::lto::run_pass_manager(cgcx, module, config, thin)
181     }
182 }
183
184 unsafe impl Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis
185 unsafe impl Sync for LlvmCodegenBackend {}
186
187 impl LlvmCodegenBackend {
188     pub fn new() -> Box<dyn CodegenBackend> {
189         Box::new(LlvmCodegenBackend(()))
190     }
191 }
192
193 impl CodegenBackend for LlvmCodegenBackend {
194     fn init(&self, sess: &Session) {
195         llvm_util::init(sess); // Make sure llvm is inited
196     }
197
198     fn print(&self, req: PrintRequest, sess: &Session) {
199         match req {
200             PrintRequest::RelocationModels => {
201                 println!("Available relocation models:");
202                 for name in
203                     &["static", "pic", "dynamic-no-pic", "ropi", "rwpi", "ropi-rwpi", "default"]
204                 {
205                     println!("    {}", name);
206                 }
207                 println!();
208             }
209             PrintRequest::CodeModels => {
210                 println!("Available code models:");
211                 for name in &["tiny", "small", "kernel", "medium", "large"] {
212                     println!("    {}", name);
213                 }
214                 println!();
215             }
216             PrintRequest::TlsModels => {
217                 println!("Available TLS models:");
218                 for name in &["global-dynamic", "local-dynamic", "initial-exec", "local-exec"] {
219                     println!("    {}", name);
220                 }
221                 println!();
222             }
223             req => llvm_util::print(req, sess),
224         }
225     }
226
227     fn print_passes(&self) {
228         llvm_util::print_passes();
229     }
230
231     fn print_version(&self) {
232         llvm_util::print_version();
233     }
234
235     fn target_features(&self, sess: &Session) -> Vec<Symbol> {
236         target_features(sess)
237     }
238
239     fn metadata_loader(&self) -> Box<MetadataLoaderDyn> {
240         Box::new(metadata::LlvmMetadataLoader)
241     }
242
243     fn provide(&self, providers: &mut ty::query::Providers<'_>) {
244         attributes::provide(providers);
245     }
246
247     fn provide_extern(&self, providers: &mut ty::query::Providers<'_>) {
248         attributes::provide_extern(providers);
249     }
250
251     fn codegen_crate<'tcx>(
252         &self,
253         tcx: TyCtxt<'tcx>,
254         metadata: EncodedMetadata,
255         need_metadata_module: bool,
256     ) -> Box<dyn Any> {
257         Box::new(rustc_codegen_ssa::base::codegen_crate(
258             LlvmCodegenBackend(()),
259             tcx,
260             metadata,
261             need_metadata_module,
262         ))
263     }
264
265     fn join_codegen(
266         &self,
267         ongoing_codegen: Box<dyn Any>,
268         sess: &Session,
269         dep_graph: &DepGraph,
270     ) -> Result<Box<dyn Any>, ErrorReported> {
271         let (codegen_results, work_products) = ongoing_codegen
272             .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
273             .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
274             .join(sess);
275         if sess.opts.debugging_opts.incremental_info {
276             rustc_codegen_ssa::back::write::dump_incremental_data(&codegen_results);
277         }
278
279         sess.time("serialize_work_products", move || {
280             rustc_incremental::save_work_product_index(sess, &dep_graph, work_products)
281         });
282
283         sess.compile_status()?;
284
285         Ok(Box::new(codegen_results))
286     }
287
288     fn link(
289         &self,
290         sess: &Session,
291         codegen_results: Box<dyn Any>,
292         outputs: &OutputFilenames,
293     ) -> Result<(), ErrorReported> {
294         let codegen_results = codegen_results
295             .downcast::<CodegenResults>()
296             .expect("Expected CodegenResults, found Box<Any>");
297
298         if sess.opts.debugging_opts.no_link {
299             // FIXME: use a binary format to encode the `.rlink` file
300             let rlink_data = json::encode(&codegen_results).map_err(|err| {
301                 sess.fatal(&format!("failed to encode rlink: {}", err));
302             })?;
303             let rlink_file = outputs.with_extension(config::RLINK_EXT);
304             fs::write(&rlink_file, rlink_data).map_err(|err| {
305                 sess.fatal(&format!("failed to write file {}: {}", rlink_file.display(), err));
306             })?;
307             return Ok(());
308         }
309
310         // Run the linker on any artifacts that resulted from the LLVM run.
311         // This should produce either a finished executable or library.
312         sess.time("link_crate", || {
313             use crate::back::archive::LlvmArchiveBuilder;
314             use rustc_codegen_ssa::back::link::link_binary;
315
316             let target_cpu = crate::llvm_util::target_cpu(sess);
317             link_binary::<LlvmArchiveBuilder<'_>>(
318                 sess,
319                 &codegen_results,
320                 outputs,
321                 &codegen_results.crate_name.as_str(),
322                 target_cpu,
323             );
324         });
325
326         // Now that we won't touch anything in the incremental compilation directory
327         // any more, we can finalize it (which involves renaming it)
328         rustc_incremental::finalize_session_directory(sess, codegen_results.crate_hash);
329
330         sess.time("llvm_dump_timing_file", || {
331             if sess.opts.debugging_opts.llvm_time_trace {
332                 llvm_util::time_trace_profiler_finish("llvm_timings.json");
333             }
334         });
335
336         Ok(())
337     }
338 }
339
340 pub struct ModuleLlvm {
341     llcx: &'static mut llvm::Context,
342     llmod_raw: *const llvm::Module,
343     tm: &'static mut llvm::TargetMachine,
344 }
345
346 unsafe impl Send for ModuleLlvm {}
347 unsafe impl Sync for ModuleLlvm {}
348
349 impl ModuleLlvm {
350     fn new(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
351         unsafe {
352             let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
353             let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
354             ModuleLlvm { llmod_raw, llcx, tm: create_target_machine(tcx) }
355         }
356     }
357
358     fn new_metadata(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
359         unsafe {
360             let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
361             let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
362             ModuleLlvm { llmod_raw, llcx, tm: create_informational_target_machine(tcx.sess) }
363         }
364     }
365
366     fn parse(
367         cgcx: &CodegenContext<LlvmCodegenBackend>,
368         name: &CStr,
369         buffer: &[u8],
370         handler: &Handler,
371     ) -> Result<Self, FatalError> {
372         unsafe {
373             let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
374             let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?;
375             let tm = match (cgcx.tm_factory.0)() {
376                 Ok(m) => m,
377                 Err(e) => {
378                     handler.struct_err(&e).emit();
379                     return Err(FatalError);
380                 }
381             };
382
383             Ok(ModuleLlvm { llmod_raw, llcx, tm })
384         }
385     }
386
387     fn llmod(&self) -> &llvm::Module {
388         unsafe { &*self.llmod_raw }
389     }
390 }
391
392 impl Drop for ModuleLlvm {
393     fn drop(&mut self) {
394         unsafe {
395             llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
396             llvm::LLVMRustDisposeTargetMachine(&mut *(self.tm as *mut _));
397         }
398     }
399 }