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