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