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