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