]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | use back::lto; | |
c1a9b12d | 12 | use back::link::{get_linker, remove}; |
9e0c209e | 13 | use rustc_incremental::{save_trans_partition, in_incr_comp_dir}; |
5bcae85e | 14 | use session::config::{OutputFilenames, OutputTypes, Passes, SomePasses, AllPasses}; |
1a4d82fc | 15 | use session::Session; |
b039eaaf | 16 | use session::config::{self, OutputType}; |
1a4d82fc JJ |
17 | use llvm; |
18 | use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef}; | |
19 | use llvm::SMDiagnosticRef; | |
5bcae85e | 20 | use {CrateTranslation, ModuleLlvm, ModuleSource, ModuleTranslation}; |
1a4d82fc | 21 | use util::common::time; |
c34b1796 | 22 | use util::common::path2cstr; |
5bcae85e SL |
23 | use util::fs::link_or_copy; |
24 | use errors::{self, Handler, Level, DiagnosticBuilder}; | |
25 | use errors::emitter::Emitter; | |
3157f602 | 26 | use syntax_pos::MultiSpan; |
5bcae85e | 27 | use context::{is_pie_binary, get_reloc_model}; |
1a4d82fc | 28 | |
85aaf69f | 29 | use std::ffi::{CStr, CString}; |
c34b1796 | 30 | use std::fs; |
b039eaaf | 31 | use std::path::{Path, PathBuf}; |
1a4d82fc | 32 | use std::str; |
1a4d82fc JJ |
33 | use std::sync::{Arc, Mutex}; |
34 | use std::sync::mpsc::channel; | |
35 | use std::thread; | |
a7813a04 | 36 | use libc::{c_uint, c_void}; |
1a4d82fc | 37 | |
5bcae85e SL |
38 | pub const RELOC_MODEL_ARGS : [(&'static str, llvm::RelocMode); 4] = [ |
39 | ("pic", llvm::RelocMode::PIC), | |
40 | ("static", llvm::RelocMode::Static), | |
41 | ("default", llvm::RelocMode::Default), | |
42 | ("dynamic-no-pic", llvm::RelocMode::DynamicNoPic), | |
43 | ]; | |
44 | ||
45 | pub const CODE_GEN_MODEL_ARGS : [(&'static str, llvm::CodeModel); 5] = [ | |
46 | ("default", llvm::CodeModel::Default), | |
47 | ("small", llvm::CodeModel::Small), | |
48 | ("kernel", llvm::CodeModel::Kernel), | |
49 | ("medium", llvm::CodeModel::Medium), | |
50 | ("large", llvm::CodeModel::Large), | |
51 | ]; | |
52 | ||
9cc50fc6 | 53 | pub fn llvm_err(handler: &errors::Handler, msg: String) -> ! { |
7453a54e SL |
54 | match llvm::last_error() { |
55 | Some(err) => panic!(handler.fatal(&format!("{}: {}", msg, err))), | |
56 | None => panic!(handler.fatal(&msg)), | |
1a4d82fc JJ |
57 | } |
58 | } | |
59 | ||
60 | pub fn write_output_file( | |
9cc50fc6 | 61 | handler: &errors::Handler, |
1a4d82fc JJ |
62 | target: llvm::TargetMachineRef, |
63 | pm: llvm::PassManagerRef, | |
64 | m: ModuleRef, | |
65 | output: &Path, | |
66 | file_type: llvm::FileType) { | |
67 | unsafe { | |
c34b1796 | 68 | let output_c = path2cstr(output); |
1a4d82fc | 69 | let result = llvm::LLVMRustWriteOutputFile( |
85aaf69f | 70 | target, pm, m, output_c.as_ptr(), file_type); |
5bcae85e | 71 | if result.into_result().is_err() { |
85aaf69f | 72 | llvm_err(handler, format!("could not write output to {}", output.display())); |
1a4d82fc JJ |
73 | } |
74 | } | |
75 | } | |
76 | ||
77 | ||
78 | struct Diagnostic { | |
79 | msg: String, | |
80 | code: Option<String>, | |
81 | lvl: Level, | |
82 | } | |
83 | ||
84 | // We use an Arc instead of just returning a list of diagnostics from the | |
bd371182 AL |
85 | // child thread because we need to make sure that the messages are seen even |
86 | // if the child thread panics (for example, when `fatal` is called). | |
1a4d82fc JJ |
87 | #[derive(Clone)] |
88 | struct SharedEmitter { | |
89 | buffer: Arc<Mutex<Vec<Diagnostic>>>, | |
90 | } | |
91 | ||
92 | impl SharedEmitter { | |
93 | fn new() -> SharedEmitter { | |
94 | SharedEmitter { | |
95 | buffer: Arc::new(Mutex::new(Vec::new())), | |
96 | } | |
97 | } | |
98 | ||
99 | fn dump(&mut self, handler: &Handler) { | |
100 | let mut buffer = self.buffer.lock().unwrap(); | |
85aaf69f | 101 | for diag in &*buffer { |
1a4d82fc JJ |
102 | match diag.code { |
103 | Some(ref code) => { | |
a7813a04 | 104 | handler.emit_with_code(&MultiSpan::new(), |
c34b1796 | 105 | &diag.msg, |
85aaf69f | 106 | &code[..], |
1a4d82fc JJ |
107 | diag.lvl); |
108 | }, | |
109 | None => { | |
a7813a04 | 110 | handler.emit(&MultiSpan::new(), |
c34b1796 | 111 | &diag.msg, |
1a4d82fc JJ |
112 | diag.lvl); |
113 | }, | |
114 | } | |
115 | } | |
116 | buffer.clear(); | |
117 | } | |
118 | } | |
119 | ||
5bcae85e SL |
120 | impl Emitter for SharedEmitter { |
121 | fn emit(&mut self, db: &DiagnosticBuilder) { | |
1a4d82fc | 122 | self.buffer.lock().unwrap().push(Diagnostic { |
5bcae85e SL |
123 | msg: db.message.to_string(), |
124 | code: db.code.clone(), | |
125 | lvl: db.level, | |
1a4d82fc | 126 | }); |
5bcae85e SL |
127 | for child in &db.children { |
128 | self.buffer.lock().unwrap().push(Diagnostic { | |
129 | msg: child.message.to_string(), | |
130 | code: None, | |
131 | lvl: child.level, | |
132 | }); | |
133 | } | |
1a4d82fc | 134 | } |
1a4d82fc JJ |
135 | } |
136 | ||
1a4d82fc JJ |
137 | // On android, we by default compile for armv7 processors. This enables |
138 | // things like double word CAS instructions (rather than emulating them) | |
139 | // which are *far* more efficient. This is obviously undesirable in some | |
140 | // cases, so if any sort of target feature is specified we don't append v7 | |
141 | // to the feature list. | |
142 | // | |
143 | // On iOS only armv7 and newer are supported. So it is useful to | |
144 | // get all hardware potential via VFP3 (hardware floating point) | |
145 | // and NEON (SIMD) instructions supported by LLVM. | |
146 | // Note that without those flags various linking errors might | |
147 | // arise as some of intrinsics are converted into function calls | |
148 | // and nobody provides implementations those functions | |
149 | fn target_feature(sess: &Session) -> String { | |
150 | format!("{},{}", sess.target.target.options.features, sess.opts.cg.target_feature) | |
151 | } | |
152 | ||
153 | fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel { | |
154 | match optimize { | |
5bcae85e SL |
155 | config::OptLevel::No => llvm::CodeGenOptLevel::None, |
156 | config::OptLevel::Less => llvm::CodeGenOptLevel::Less, | |
157 | config::OptLevel::Default => llvm::CodeGenOptLevel::Default, | |
158 | config::OptLevel::Aggressive => llvm::CodeGenOptLevel::Aggressive, | |
159 | _ => llvm::CodeGenOptLevel::Default, | |
a7813a04 XL |
160 | } |
161 | } | |
162 | ||
163 | fn get_llvm_opt_size(optimize: config::OptLevel) -> llvm::CodeGenOptSize { | |
164 | match optimize { | |
165 | config::OptLevel::Size => llvm::CodeGenOptSizeDefault, | |
166 | config::OptLevel::SizeMin => llvm::CodeGenOptSizeAggressive, | |
167 | _ => llvm::CodeGenOptSizeNone, | |
1a4d82fc JJ |
168 | } |
169 | } | |
170 | ||
c1a9b12d | 171 | pub fn create_target_machine(sess: &Session) -> TargetMachineRef { |
5bcae85e | 172 | let reloc_model = get_reloc_model(sess); |
1a4d82fc JJ |
173 | |
174 | let opt_level = get_llvm_opt_level(sess.opts.optimize); | |
175 | let use_softfp = sess.opts.cg.soft_float; | |
176 | ||
1a4d82fc JJ |
177 | let ffunction_sections = sess.target.target.options.function_sections; |
178 | let fdata_sections = ffunction_sections; | |
179 | ||
180 | let code_model_arg = match sess.opts.cg.code_model { | |
85aaf69f | 181 | Some(ref s) => &s[..], |
c34b1796 | 182 | None => &sess.target.target.options.code_model[..], |
1a4d82fc JJ |
183 | }; |
184 | ||
5bcae85e SL |
185 | let code_model = match CODE_GEN_MODEL_ARGS.iter().find( |
186 | |&&arg| arg.0 == code_model_arg) { | |
187 | Some(x) => x.1, | |
1a4d82fc JJ |
188 | _ => { |
189 | sess.err(&format!("{:?} is not a valid code model", | |
190 | sess.opts | |
191 | .cg | |
c34b1796 | 192 | .code_model)); |
1a4d82fc | 193 | sess.abort_if_errors(); |
54a0048b | 194 | bug!(); |
1a4d82fc JJ |
195 | } |
196 | }; | |
197 | ||
c34b1796 | 198 | let triple = &sess.target.target.llvm_target; |
1a4d82fc JJ |
199 | |
200 | let tm = unsafe { | |
85aaf69f | 201 | let triple = CString::new(triple.as_bytes()).unwrap(); |
1a4d82fc | 202 | let cpu = match sess.opts.cg.target_cpu { |
85aaf69f SL |
203 | Some(ref s) => &**s, |
204 | None => &*sess.target.target.options.cpu | |
1a4d82fc | 205 | }; |
85aaf69f SL |
206 | let cpu = CString::new(cpu.as_bytes()).unwrap(); |
207 | let features = CString::new(target_feature(sess).as_bytes()).unwrap(); | |
1a4d82fc JJ |
208 | llvm::LLVMRustCreateTargetMachine( |
209 | triple.as_ptr(), cpu.as_ptr(), features.as_ptr(), | |
210 | code_model, | |
211 | reloc_model, | |
212 | opt_level, | |
1a4d82fc | 213 | use_softfp, |
5bcae85e | 214 | is_pie_binary(sess), |
1a4d82fc JJ |
215 | ffunction_sections, |
216 | fdata_sections, | |
217 | ) | |
218 | }; | |
219 | ||
220 | if tm.is_null() { | |
9cc50fc6 | 221 | llvm_err(sess.diagnostic(), |
1a4d82fc JJ |
222 | format!("Could not create LLVM TargetMachine for triple: {}", |
223 | triple).to_string()); | |
224 | } else { | |
225 | return tm; | |
226 | }; | |
227 | } | |
228 | ||
229 | ||
230 | /// Module-specific configuration for `optimize_and_codegen`. | |
231 | #[derive(Clone)] | |
c1a9b12d | 232 | pub struct ModuleConfig { |
1a4d82fc JJ |
233 | /// LLVM TargetMachine to use for codegen. |
234 | tm: TargetMachineRef, | |
235 | /// Names of additional optimization passes to run. | |
236 | passes: Vec<String>, | |
237 | /// Some(level) to optimize at a certain level, or None to run | |
238 | /// absolutely no optimizations (used for the metadata module). | |
239 | opt_level: Option<llvm::CodeGenOptLevel>, | |
240 | ||
a7813a04 XL |
241 | /// Some(level) to optimize binary size, or None to not affect program size. |
242 | opt_size: Option<llvm::CodeGenOptSize>, | |
243 | ||
1a4d82fc JJ |
244 | // Flags indicating which outputs to produce. |
245 | emit_no_opt_bc: bool, | |
246 | emit_bc: bool, | |
247 | emit_lto_bc: bool, | |
248 | emit_ir: bool, | |
249 | emit_asm: bool, | |
250 | emit_obj: bool, | |
1a4d82fc JJ |
251 | // Miscellaneous flags. These are mostly copied from command-line |
252 | // options. | |
253 | no_verify: bool, | |
254 | no_prepopulate_passes: bool, | |
255 | no_builtins: bool, | |
256 | time_passes: bool, | |
62682a34 SL |
257 | vectorize_loop: bool, |
258 | vectorize_slp: bool, | |
259 | merge_functions: bool, | |
7453a54e SL |
260 | inline_threshold: Option<usize>, |
261 | // Instead of creating an object file by doing LLVM codegen, just | |
262 | // make the object file bitcode. Provides easy compatibility with | |
263 | // emscripten's ecc compiler, when used as the linker. | |
264 | obj_is_bitcode: bool, | |
1a4d82fc JJ |
265 | } |
266 | ||
267 | unsafe impl Send for ModuleConfig { } | |
268 | ||
269 | impl ModuleConfig { | |
270 | fn new(tm: TargetMachineRef, passes: Vec<String>) -> ModuleConfig { | |
271 | ModuleConfig { | |
272 | tm: tm, | |
273 | passes: passes, | |
274 | opt_level: None, | |
a7813a04 | 275 | opt_size: None, |
1a4d82fc JJ |
276 | |
277 | emit_no_opt_bc: false, | |
278 | emit_bc: false, | |
279 | emit_lto_bc: false, | |
280 | emit_ir: false, | |
281 | emit_asm: false, | |
282 | emit_obj: false, | |
7453a54e | 283 | obj_is_bitcode: false, |
1a4d82fc JJ |
284 | |
285 | no_verify: false, | |
286 | no_prepopulate_passes: false, | |
287 | no_builtins: false, | |
288 | time_passes: false, | |
62682a34 SL |
289 | vectorize_loop: false, |
290 | vectorize_slp: false, | |
291 | merge_functions: false, | |
92a42be0 | 292 | inline_threshold: None |
1a4d82fc JJ |
293 | } |
294 | } | |
295 | ||
296 | fn set_flags(&mut self, sess: &Session, trans: &CrateTranslation) { | |
297 | self.no_verify = sess.no_verify(); | |
298 | self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes; | |
299 | self.no_builtins = trans.no_builtins; | |
300 | self.time_passes = sess.time_passes(); | |
92a42be0 | 301 | self.inline_threshold = sess.opts.cg.inline_threshold; |
7453a54e | 302 | self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode; |
62682a34 SL |
303 | |
304 | // Copy what clang does by turning on loop vectorization at O2 and | |
305 | // slp vectorization at O3. Otherwise configure other optimization aspects | |
306 | // of this pass manager builder. | |
307 | self.vectorize_loop = !sess.opts.cg.no_vectorize_loops && | |
9cc50fc6 SL |
308 | (sess.opts.optimize == config::OptLevel::Default || |
309 | sess.opts.optimize == config::OptLevel::Aggressive); | |
62682a34 | 310 | self.vectorize_slp = !sess.opts.cg.no_vectorize_slp && |
9cc50fc6 | 311 | sess.opts.optimize == config::OptLevel::Aggressive; |
62682a34 | 312 | |
9cc50fc6 SL |
313 | self.merge_functions = sess.opts.optimize == config::OptLevel::Default || |
314 | sess.opts.optimize == config::OptLevel::Aggressive; | |
1a4d82fc JJ |
315 | } |
316 | } | |
317 | ||
318 | /// Additional resources used by optimize_and_codegen (not module specific) | |
319 | struct CodegenContext<'a> { | |
320 | // Extra resources used for LTO: (sess, reachable). This will be `None` | |
321 | // when running in a worker thread. | |
322 | lto_ctxt: Option<(&'a Session, &'a [String])>, | |
323 | // Handler to use for diagnostics produced during codegen. | |
324 | handler: &'a Handler, | |
9346a6ac AL |
325 | // LLVM passes added by plugins. |
326 | plugin_passes: Vec<String>, | |
1a4d82fc JJ |
327 | // LLVM optimizations for which we want to print remarks. |
328 | remark: Passes, | |
b039eaaf SL |
329 | // Worker thread number |
330 | worker: usize, | |
9e0c209e SL |
331 | // The incremental compilation session directory, or None if we are not |
332 | // compiling incrementally | |
333 | incr_comp_session_dir: Option<PathBuf> | |
1a4d82fc JJ |
334 | } |
335 | ||
336 | impl<'a> CodegenContext<'a> { | |
337 | fn new_with_session(sess: &'a Session, reachable: &'a [String]) -> CodegenContext<'a> { | |
338 | CodegenContext { | |
339 | lto_ctxt: Some((sess, reachable)), | |
9cc50fc6 | 340 | handler: sess.diagnostic(), |
9346a6ac | 341 | plugin_passes: sess.plugin_llvm_passes.borrow().clone(), |
1a4d82fc | 342 | remark: sess.opts.cg.remark.clone(), |
b039eaaf | 343 | worker: 0, |
9e0c209e | 344 | incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()) |
1a4d82fc JJ |
345 | } |
346 | } | |
347 | } | |
348 | ||
349 | struct HandlerFreeVars<'a> { | |
350 | llcx: ContextRef, | |
351 | cgcx: &'a CodegenContext<'a>, | |
352 | } | |
353 | ||
85aaf69f | 354 | unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext<'a>, |
62682a34 SL |
355 | msg: &'b str, |
356 | cookie: c_uint) { | |
3157f602 | 357 | use syntax_pos::ExpnId; |
1a4d82fc | 358 | |
1a4d82fc JJ |
359 | match cgcx.lto_ctxt { |
360 | Some((sess, _)) => { | |
d9579d0f | 361 | sess.codemap().with_expn_info(ExpnId::from_u32(cookie), |info| match info { |
85aaf69f SL |
362 | Some(ei) => sess.span_err(ei.call_site, msg), |
363 | None => sess.err(msg), | |
1a4d82fc JJ |
364 | }); |
365 | } | |
366 | ||
367 | None => { | |
9cc50fc6 SL |
368 | cgcx.handler.struct_err(msg) |
369 | .note("build without -C codegen-units for more exact errors") | |
370 | .emit(); | |
1a4d82fc JJ |
371 | } |
372 | } | |
373 | } | |
374 | ||
85aaf69f SL |
375 | unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef, |
376 | user: *const c_void, | |
377 | cookie: c_uint) { | |
e9174d1e | 378 | let HandlerFreeVars { cgcx, .. } = *(user as *const HandlerFreeVars); |
85aaf69f | 379 | |
5bcae85e | 380 | let msg = llvm::build_string(|s| llvm::LLVMRustWriteSMDiagnosticToString(diag, s)) |
85aaf69f SL |
381 | .expect("non-UTF8 SMDiagnostic"); |
382 | ||
383 | report_inline_asm(cgcx, &msg[..], cookie); | |
384 | } | |
385 | ||
1a4d82fc | 386 | unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_void) { |
e9174d1e | 387 | let HandlerFreeVars { llcx, cgcx } = *(user as *const HandlerFreeVars); |
1a4d82fc JJ |
388 | |
389 | match llvm::diagnostic::Diagnostic::unpack(info) { | |
85aaf69f SL |
390 | llvm::diagnostic::InlineAsm(inline) => { |
391 | report_inline_asm(cgcx, | |
7453a54e | 392 | &llvm::twine_to_string(inline.message), |
85aaf69f SL |
393 | inline.cookie); |
394 | } | |
395 | ||
1a4d82fc | 396 | llvm::diagnostic::Optimization(opt) => { |
85aaf69f | 397 | let pass_name = str::from_utf8(CStr::from_ptr(opt.pass_name).to_bytes()) |
1a4d82fc JJ |
398 | .ok() |
399 | .expect("got a non-UTF8 pass name from LLVM"); | |
400 | let enabled = match cgcx.remark { | |
401 | AllPasses => true, | |
402 | SomePasses(ref v) => v.iter().any(|s| *s == pass_name), | |
403 | }; | |
404 | ||
405 | if enabled { | |
406 | let loc = llvm::debug_loc_to_string(llcx, opt.debug_loc); | |
9cc50fc6 SL |
407 | cgcx.handler.note_without_error(&format!("optimization {} for {} at {}: {}", |
408 | opt.kind.describe(), | |
409 | pass_name, | |
410 | if loc.is_empty() { "[unknown]" } else { &*loc }, | |
411 | llvm::twine_to_string(opt.message))); | |
1a4d82fc JJ |
412 | } |
413 | } | |
414 | ||
415 | _ => (), | |
416 | } | |
417 | } | |
418 | ||
419 | // Unsafe due to LLVM calls. | |
420 | unsafe fn optimize_and_codegen(cgcx: &CodegenContext, | |
421 | mtrans: ModuleTranslation, | |
5bcae85e | 422 | mllvm: ModuleLlvm, |
1a4d82fc | 423 | config: ModuleConfig, |
1a4d82fc | 424 | output_names: OutputFilenames) { |
5bcae85e SL |
425 | let llmod = mllvm.llmod; |
426 | let llcx = mllvm.llcx; | |
1a4d82fc JJ |
427 | let tm = config.tm; |
428 | ||
429 | // llcx doesn't outlive this function, so we can put this on the stack. | |
430 | let fv = HandlerFreeVars { | |
431 | llcx: llcx, | |
432 | cgcx: cgcx, | |
433 | }; | |
434 | let fv = &fv as *const HandlerFreeVars as *mut c_void; | |
435 | ||
5bcae85e | 436 | llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, fv); |
85aaf69f | 437 | llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, fv); |
1a4d82fc | 438 | |
5bcae85e SL |
439 | let module_name = Some(&mtrans.name[..]); |
440 | ||
1a4d82fc | 441 | if config.emit_no_opt_bc { |
5bcae85e | 442 | let out = output_names.temp_path_ext("no-opt.bc", module_name); |
c34b1796 | 443 | let out = path2cstr(&out); |
1a4d82fc JJ |
444 | llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); |
445 | } | |
446 | ||
c1a9b12d SL |
447 | if config.opt_level.is_some() { |
448 | // Create the two optimizing pass managers. These mirror what clang | |
449 | // does, and are by populated by LLVM's default PassManagerBuilder. | |
450 | // Each manager has a different set of passes, but they also share | |
451 | // some common passes. | |
452 | let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod); | |
453 | let mpm = llvm::LLVMCreatePassManager(); | |
454 | ||
455 | // If we're verifying or linting, add them to the function pass | |
456 | // manager. | |
7453a54e SL |
457 | let addpass = |pass_name: &str| { |
458 | let pass_name = CString::new(pass_name).unwrap(); | |
459 | let pass = llvm::LLVMRustFindAndCreatePass(pass_name.as_ptr()); | |
460 | if pass.is_null() { | |
461 | return false; | |
462 | } | |
463 | let pass_manager = match llvm::LLVMRustPassKind(pass) { | |
5bcae85e SL |
464 | llvm::PassKind::Function => fpm, |
465 | llvm::PassKind::Module => mpm, | |
466 | llvm::PassKind::Other => { | |
7453a54e SL |
467 | cgcx.handler.err("Encountered LLVM pass kind we can't handle"); |
468 | return true | |
469 | }, | |
470 | }; | |
471 | llvm::LLVMRustAddPass(pass_manager, pass); | |
472 | true | |
c1a9b12d | 473 | }; |
1a4d82fc | 474 | |
c1a9b12d SL |
475 | if !config.no_verify { assert!(addpass("verify")); } |
476 | if !config.no_prepopulate_passes { | |
477 | llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod); | |
478 | llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod); | |
479 | with_llvm_pmb(llmod, &config, &mut |b| { | |
480 | llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm); | |
481 | llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm); | |
482 | }) | |
483 | } | |
1a4d82fc | 484 | |
c1a9b12d SL |
485 | for pass in &config.passes { |
486 | if !addpass(pass) { | |
487 | cgcx.handler.warn(&format!("unknown pass `{}`, ignoring", | |
488 | pass)); | |
1a4d82fc | 489 | } |
c1a9b12d | 490 | } |
1a4d82fc | 491 | |
c1a9b12d SL |
492 | for pass in &cgcx.plugin_passes { |
493 | if !addpass(pass) { | |
494 | cgcx.handler.err(&format!("a plugin asked for LLVM pass \ | |
495 | `{}` but LLVM does not \ | |
496 | recognize it", pass)); | |
9346a6ac | 497 | } |
c1a9b12d | 498 | } |
9346a6ac | 499 | |
c1a9b12d | 500 | cgcx.handler.abort_if_errors(); |
9346a6ac | 501 | |
c1a9b12d | 502 | // Finally, run the actual optimization passes |
b039eaaf | 503 | time(config.time_passes, &format!("llvm function passes [{}]", cgcx.worker), || |
c1a9b12d | 504 | llvm::LLVMRustRunFunctionPassManager(fpm, llmod)); |
b039eaaf | 505 | time(config.time_passes, &format!("llvm module passes [{}]", cgcx.worker), || |
c1a9b12d | 506 | llvm::LLVMRunPassManager(mpm, llmod)); |
1a4d82fc | 507 | |
c1a9b12d SL |
508 | // Deallocate managers that we're now done with |
509 | llvm::LLVMDisposePassManager(fpm); | |
510 | llvm::LLVMDisposePassManager(mpm); | |
1a4d82fc | 511 | |
c1a9b12d SL |
512 | match cgcx.lto_ctxt { |
513 | Some((sess, reachable)) if sess.lto() => { | |
5bcae85e SL |
514 | time(sess.time_passes(), "all lto passes", || { |
515 | let temp_no_opt_bc_filename = | |
516 | output_names.temp_path_ext("no-opt.lto.bc", module_name); | |
517 | lto::run(sess, | |
518 | llmod, | |
519 | tm, | |
520 | reachable, | |
521 | &config, | |
522 | &temp_no_opt_bc_filename); | |
523 | }); | |
c1a9b12d | 524 | if config.emit_lto_bc { |
5bcae85e | 525 | let out = output_names.temp_path_ext("lto.bc", module_name); |
c1a9b12d SL |
526 | let out = path2cstr(&out); |
527 | llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); | |
528 | } | |
529 | }, | |
530 | _ => {}, | |
531 | } | |
1a4d82fc JJ |
532 | } |
533 | ||
534 | // A codegen-specific pass manager is used to generate object | |
535 | // files for an LLVM module. | |
536 | // | |
537 | // Apparently each of these pass managers is a one-shot kind of | |
538 | // thing, so we create a new one for each type of output. The | |
539 | // pass manager passed to the closure should be ensured to not | |
540 | // escape the closure itself, and the manager should only be | |
541 | // used once. | |
542 | unsafe fn with_codegen<F>(tm: TargetMachineRef, | |
543 | llmod: ModuleRef, | |
544 | no_builtins: bool, | |
545 | f: F) where | |
546 | F: FnOnce(PassManagerRef), | |
547 | { | |
548 | let cpm = llvm::LLVMCreatePassManager(); | |
549 | llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod); | |
550 | llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); | |
551 | f(cpm); | |
1a4d82fc JJ |
552 | } |
553 | ||
7453a54e SL |
554 | // Change what we write and cleanup based on whether obj files are |
555 | // just llvm bitcode. In that case write bitcode, and possibly | |
556 | // delete the bitcode if it wasn't requested. Don't generate the | |
557 | // machine code, instead copy the .o file from the .bc | |
558 | let write_bc = config.emit_bc || config.obj_is_bitcode; | |
559 | let rm_bc = !config.emit_bc && config.obj_is_bitcode; | |
560 | let write_obj = config.emit_obj && !config.obj_is_bitcode; | |
561 | let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode; | |
562 | ||
5bcae85e SL |
563 | let bc_out = output_names.temp_path(OutputType::Bitcode, module_name); |
564 | let obj_out = output_names.temp_path(OutputType::Object, module_name); | |
7453a54e SL |
565 | |
566 | if write_bc { | |
567 | let bc_out_c = path2cstr(&bc_out); | |
568 | llvm::LLVMWriteBitcodeToFile(llmod, bc_out_c.as_ptr()); | |
1a4d82fc JJ |
569 | } |
570 | ||
b039eaaf | 571 | time(config.time_passes, &format!("codegen passes [{}]", cgcx.worker), || { |
1a4d82fc | 572 | if config.emit_ir { |
5bcae85e | 573 | let out = output_names.temp_path(OutputType::LlvmAssembly, module_name); |
c34b1796 | 574 | let out = path2cstr(&out); |
1a4d82fc JJ |
575 | with_codegen(tm, llmod, config.no_builtins, |cpm| { |
576 | llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr()); | |
62682a34 | 577 | llvm::LLVMDisposePassManager(cpm); |
1a4d82fc JJ |
578 | }) |
579 | } | |
580 | ||
581 | if config.emit_asm { | |
5bcae85e | 582 | let path = output_names.temp_path(OutputType::Assembly, module_name); |
9cc50fc6 SL |
583 | |
584 | // We can't use the same module for asm and binary output, because that triggers | |
585 | // various errors like invalid IR or broken binaries, so we might have to clone the | |
586 | // module to produce the asm output | |
587 | let llmod = if config.emit_obj { | |
588 | llvm::LLVMCloneModule(llmod) | |
589 | } else { | |
590 | llmod | |
591 | }; | |
1a4d82fc | 592 | with_codegen(tm, llmod, config.no_builtins, |cpm| { |
62682a34 | 593 | write_output_file(cgcx.handler, tm, cpm, llmod, &path, |
5bcae85e | 594 | llvm::FileType::AssemblyFile); |
1a4d82fc | 595 | }); |
9cc50fc6 SL |
596 | if config.emit_obj { |
597 | llvm::LLVMDisposeModule(llmod); | |
598 | } | |
1a4d82fc JJ |
599 | } |
600 | ||
7453a54e | 601 | if write_obj { |
1a4d82fc | 602 | with_codegen(tm, llmod, config.no_builtins, |cpm| { |
5bcae85e SL |
603 | write_output_file(cgcx.handler, tm, cpm, llmod, &obj_out, |
604 | llvm::FileType::ObjectFile); | |
1a4d82fc JJ |
605 | }); |
606 | } | |
607 | }); | |
608 | ||
7453a54e SL |
609 | if copy_bc_to_obj { |
610 | debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out); | |
5bcae85e | 611 | if let Err(e) = link_or_copy(&bc_out, &obj_out) { |
7453a54e SL |
612 | cgcx.handler.err(&format!("failed to copy bitcode to object file: {}", e)); |
613 | } | |
614 | } | |
615 | ||
616 | if rm_bc { | |
617 | debug!("removing_bitcode {:?}", bc_out); | |
618 | if let Err(e) = fs::remove_file(&bc_out) { | |
619 | cgcx.handler.err(&format!("failed to remove bitcode: {}", e)); | |
620 | } | |
621 | } | |
622 | ||
1a4d82fc JJ |
623 | llvm::LLVMRustDisposeTargetMachine(tm); |
624 | } | |
625 | ||
3157f602 XL |
626 | |
627 | pub fn cleanup_llvm(trans: &CrateTranslation) { | |
628 | for module in trans.modules.iter() { | |
629 | unsafe { | |
5bcae85e SL |
630 | match module.source { |
631 | ModuleSource::Translated(llvm) => { | |
632 | llvm::LLVMDisposeModule(llvm.llmod); | |
633 | llvm::LLVMContextDispose(llvm.llcx); | |
634 | } | |
635 | ModuleSource::Preexisting(_) => { | |
636 | } | |
637 | } | |
3157f602 XL |
638 | } |
639 | } | |
640 | } | |
641 | ||
1a4d82fc JJ |
642 | pub fn run_passes(sess: &Session, |
643 | trans: &CrateTranslation, | |
5bcae85e | 644 | output_types: &OutputTypes, |
1a4d82fc JJ |
645 | crate_output: &OutputFilenames) { |
646 | // It's possible that we have `codegen_units > 1` but only one item in | |
647 | // `trans.modules`. We could theoretically proceed and do LTO in that | |
648 | // case, but it would be confusing to have the validity of | |
649 | // `-Z lto -C codegen-units=2` depend on details of the crate being | |
650 | // compiled, so we complain regardless. | |
651 | if sess.lto() && sess.opts.cg.codegen_units > 1 { | |
652 | // This case is impossible to handle because LTO expects to be able | |
653 | // to combine the entire crate and all its dependencies into a | |
654 | // single compilation unit, but each codegen unit is in a separate | |
655 | // LLVM context, so they can't easily be combined. | |
656 | sess.fatal("can't perform LTO when using multiple codegen units"); | |
657 | } | |
658 | ||
659 | // Sanity check | |
a7813a04 XL |
660 | assert!(trans.modules.len() == sess.opts.cg.codegen_units || |
661 | sess.opts.debugging_opts.incremental.is_some()); | |
1a4d82fc | 662 | |
1a4d82fc JJ |
663 | let tm = create_target_machine(sess); |
664 | ||
665 | // Figure out what we actually need to build. | |
666 | ||
667 | let mut modules_config = ModuleConfig::new(tm, sess.opts.cg.passes.clone()); | |
c30ab7b3 | 668 | let mut metadata_config = ModuleConfig::new(tm, vec![]); |
1a4d82fc JJ |
669 | |
670 | modules_config.opt_level = Some(get_llvm_opt_level(sess.opts.optimize)); | |
a7813a04 | 671 | modules_config.opt_size = Some(get_llvm_opt_size(sess.opts.optimize)); |
1a4d82fc JJ |
672 | |
673 | // Save all versions of the bytecode if we're saving our temporaries. | |
674 | if sess.opts.cg.save_temps { | |
675 | modules_config.emit_no_opt_bc = true; | |
676 | modules_config.emit_bc = true; | |
677 | modules_config.emit_lto_bc = true; | |
678 | metadata_config.emit_bc = true; | |
679 | } | |
680 | ||
681 | // Emit bitcode files for the crate if we're emitting an rlib. | |
682 | // Whenever an rlib is created, the bitcode is inserted into the | |
683 | // archive in order to allow LTO against it. | |
684 | let needs_crate_bitcode = | |
685 | sess.crate_types.borrow().contains(&config::CrateTypeRlib) && | |
b039eaaf | 686 | sess.opts.output_types.contains_key(&OutputType::Exe); |
c1a9b12d | 687 | let needs_crate_object = |
b039eaaf | 688 | sess.opts.output_types.contains_key(&OutputType::Exe); |
1a4d82fc JJ |
689 | if needs_crate_bitcode { |
690 | modules_config.emit_bc = true; | |
691 | } | |
692 | ||
b039eaaf | 693 | for output_type in output_types.keys() { |
1a4d82fc | 694 | match *output_type { |
b039eaaf SL |
695 | OutputType::Bitcode => { modules_config.emit_bc = true; }, |
696 | OutputType::LlvmAssembly => { modules_config.emit_ir = true; }, | |
697 | OutputType::Assembly => { | |
1a4d82fc JJ |
698 | modules_config.emit_asm = true; |
699 | // If we're not using the LLVM assembler, this function | |
700 | // could be invoked specially with output_type_assembly, so | |
701 | // in this case we still want the metadata object file. | |
b039eaaf | 702 | if !sess.opts.output_types.contains_key(&OutputType::Assembly) { |
1a4d82fc JJ |
703 | metadata_config.emit_obj = true; |
704 | } | |
705 | }, | |
b039eaaf SL |
706 | OutputType::Object => { modules_config.emit_obj = true; }, |
707 | OutputType::Exe => { | |
1a4d82fc JJ |
708 | modules_config.emit_obj = true; |
709 | metadata_config.emit_obj = true; | |
710 | }, | |
b039eaaf | 711 | OutputType::DepInfo => {} |
1a4d82fc JJ |
712 | } |
713 | } | |
714 | ||
715 | modules_config.set_flags(sess, trans); | |
716 | metadata_config.set_flags(sess, trans); | |
717 | ||
718 | ||
bd371182 | 719 | // Populate a buffer with a list of codegen threads. Items are processed in |
1a4d82fc JJ |
720 | // LIFO order, just because it's a tiny bit simpler that way. (The order |
721 | // doesn't actually matter.) | |
722 | let mut work_items = Vec::with_capacity(1 + trans.modules.len()); | |
723 | ||
724 | { | |
725 | let work = build_work_item(sess, | |
5bcae85e | 726 | trans.metadata_module.clone(), |
1a4d82fc | 727 | metadata_config.clone(), |
5bcae85e | 728 | crate_output.clone()); |
1a4d82fc JJ |
729 | work_items.push(work); |
730 | } | |
731 | ||
5bcae85e | 732 | for mtrans in trans.modules.iter() { |
1a4d82fc | 733 | let work = build_work_item(sess, |
5bcae85e | 734 | mtrans.clone(), |
1a4d82fc | 735 | modules_config.clone(), |
5bcae85e | 736 | crate_output.clone()); |
1a4d82fc JJ |
737 | work_items.push(work); |
738 | } | |
739 | ||
5bcae85e SL |
740 | if sess.opts.debugging_opts.incremental_info { |
741 | dump_incremental_data(&trans); | |
742 | } | |
743 | ||
1a4d82fc | 744 | // Process the work items, optionally using worker threads. |
5bcae85e SL |
745 | // NOTE: This code is not really adapted to incremental compilation where |
746 | // the compiler decides the number of codegen units (and will | |
747 | // potentially create hundreds of them). | |
748 | let num_workers = work_items.len() - 1; | |
749 | if num_workers == 1 { | |
c34b1796 | 750 | run_work_singlethreaded(sess, &trans.reachable, work_items); |
1a4d82fc | 751 | } else { |
5bcae85e SL |
752 | run_work_multithreaded(sess, work_items, num_workers); |
753 | } | |
754 | ||
755 | // If in incr. comp. mode, preserve the `.o` files for potential re-use | |
756 | for mtrans in trans.modules.iter() { | |
757 | let mut files = vec![]; | |
758 | ||
759 | if modules_config.emit_obj { | |
760 | let path = crate_output.temp_path(OutputType::Object, Some(&mtrans.name)); | |
761 | files.push((OutputType::Object, path)); | |
762 | } | |
763 | ||
764 | if modules_config.emit_bc { | |
765 | let path = crate_output.temp_path(OutputType::Bitcode, Some(&mtrans.name)); | |
766 | files.push((OutputType::Bitcode, path)); | |
767 | } | |
768 | ||
769 | save_trans_partition(sess, &mtrans.name, mtrans.symbol_name_hash, &files); | |
1a4d82fc JJ |
770 | } |
771 | ||
772 | // All codegen is finished. | |
773 | unsafe { | |
774 | llvm::LLVMRustDisposeTargetMachine(tm); | |
775 | } | |
776 | ||
777 | // Produce final compile outputs. | |
85aaf69f SL |
778 | let copy_gracefully = |from: &Path, to: &Path| { |
779 | if let Err(e) = fs::copy(from, to) { | |
780 | sess.err(&format!("could not copy {:?} to {:?}: {}", from, to, e)); | |
781 | } | |
782 | }; | |
1a4d82fc | 783 | |
5bcae85e | 784 | let copy_if_one_unit = |output_type: OutputType, |
b039eaaf | 785 | keep_numbered: bool| { |
5bcae85e | 786 | if trans.modules.len() == 1 { |
1a4d82fc JJ |
787 | // 1) Only one codegen unit. In this case it's no difficulty |
788 | // to copy `foo.0.x` to `foo.x`. | |
5bcae85e SL |
789 | let module_name = Some(&(trans.modules[0].name)[..]); |
790 | let path = crate_output.temp_path(output_type, module_name); | |
791 | copy_gracefully(&path, | |
c1a9b12d | 792 | &crate_output.path(output_type)); |
1a4d82fc | 793 | if !sess.opts.cg.save_temps && !keep_numbered { |
5bcae85e SL |
794 | // The user just wants `foo.x`, not `foo.#module-name#.x`. |
795 | remove(sess, &path); | |
1a4d82fc JJ |
796 | } |
797 | } else { | |
5bcae85e SL |
798 | let ext = crate_output.temp_path(output_type, None) |
799 | .extension() | |
800 | .unwrap() | |
801 | .to_str() | |
802 | .unwrap() | |
803 | .to_owned(); | |
804 | ||
805 | if crate_output.outputs.contains_key(&output_type) { | |
806 | // 2) Multiple codegen units, with `--emit foo=some_name`. We have | |
807 | // no good solution for this case, so warn the user. | |
808 | sess.warn(&format!("ignoring emit path because multiple .{} files \ | |
809 | were produced", ext)); | |
810 | } else if crate_output.single_output_file.is_some() { | |
811 | // 3) Multiple codegen units, with `-o some_name`. We have | |
812 | // no good solution for this case, so warn the user. | |
813 | sess.warn(&format!("ignoring -o because multiple .{} files \ | |
814 | were produced", ext)); | |
815 | } else { | |
816 | // 4) Multiple codegen units, but no explicit name. We | |
817 | // just leave the `foo.0.x` files in place. | |
818 | // (We don't have to do any work in this case.) | |
819 | } | |
1a4d82fc JJ |
820 | } |
821 | }; | |
822 | ||
1a4d82fc JJ |
823 | // Flag to indicate whether the user explicitly requested bitcode. |
824 | // Otherwise, we produced it only as a temporary output, and will need | |
825 | // to get rid of it. | |
826 | let mut user_wants_bitcode = false; | |
c1a9b12d | 827 | let mut user_wants_objects = false; |
b039eaaf | 828 | for output_type in output_types.keys() { |
1a4d82fc | 829 | match *output_type { |
b039eaaf | 830 | OutputType::Bitcode => { |
1a4d82fc JJ |
831 | user_wants_bitcode = true; |
832 | // Copy to .bc, but always keep the .0.bc. There is a later | |
833 | // check to figure out if we should delete .0.bc files, or keep | |
834 | // them for making an rlib. | |
5bcae85e | 835 | copy_if_one_unit(OutputType::Bitcode, true); |
1a4d82fc | 836 | } |
b039eaaf | 837 | OutputType::LlvmAssembly => { |
5bcae85e | 838 | copy_if_one_unit(OutputType::LlvmAssembly, false); |
1a4d82fc | 839 | } |
b039eaaf | 840 | OutputType::Assembly => { |
5bcae85e | 841 | copy_if_one_unit(OutputType::Assembly, false); |
1a4d82fc | 842 | } |
b039eaaf | 843 | OutputType::Object => { |
c1a9b12d | 844 | user_wants_objects = true; |
5bcae85e | 845 | copy_if_one_unit(OutputType::Object, true); |
1a4d82fc | 846 | } |
b039eaaf SL |
847 | OutputType::Exe | |
848 | OutputType::DepInfo => {} | |
1a4d82fc JJ |
849 | } |
850 | } | |
851 | let user_wants_bitcode = user_wants_bitcode; | |
852 | ||
853 | // Clean up unwanted temporary files. | |
854 | ||
855 | // We create the following files by default: | |
5bcae85e SL |
856 | // - crate.#module-name#.bc |
857 | // - crate.#module-name#.o | |
1a4d82fc JJ |
858 | // - crate.metadata.bc |
859 | // - crate.metadata.o | |
860 | // - crate.o (linked from crate.##.o) | |
5bcae85e | 861 | // - crate.bc (copied from crate.##.bc) |
1a4d82fc JJ |
862 | // We may create additional files if requested by the user (through |
863 | // `-C save-temps` or `--emit=` flags). | |
864 | ||
865 | if !sess.opts.cg.save_temps { | |
5bcae85e | 866 | // Remove the temporary .#module-name#.o objects. If the user didn't |
1a4d82fc | 867 | // explicitly request bitcode (with --emit=bc), and the bitcode is not |
5bcae85e SL |
868 | // needed for building an rlib, then we must remove .#module-name#.bc as |
869 | // well. | |
1a4d82fc | 870 | |
5bcae85e | 871 | // Specific rules for keeping .#module-name#.bc: |
1a4d82fc JJ |
872 | // - If we're building an rlib (`needs_crate_bitcode`), then keep |
873 | // it. | |
874 | // - If the user requested bitcode (`user_wants_bitcode`), and | |
875 | // codegen_units > 1, then keep it. | |
876 | // - If the user requested bitcode but codegen_units == 1, then we | |
5bcae85e | 877 | // can toss .#module-name#.bc because we copied it to .bc earlier. |
1a4d82fc | 878 | // - If we're not building an rlib and the user didn't request |
5bcae85e | 879 | // bitcode, then delete .#module-name#.bc. |
1a4d82fc | 880 | // If you change how this works, also update back::link::link_rlib, |
5bcae85e SL |
881 | // where .#module-name#.bc files are (maybe) deleted after making an |
882 | // rlib. | |
1a4d82fc JJ |
883 | let keep_numbered_bitcode = needs_crate_bitcode || |
884 | (user_wants_bitcode && sess.opts.cg.codegen_units > 1); | |
885 | ||
c1a9b12d SL |
886 | let keep_numbered_objects = needs_crate_object || |
887 | (user_wants_objects && sess.opts.cg.codegen_units > 1); | |
888 | ||
5bcae85e | 889 | for module_name in trans.modules.iter().map(|m| Some(&m.name[..])) { |
c1a9b12d | 890 | if modules_config.emit_obj && !keep_numbered_objects { |
5bcae85e SL |
891 | let path = crate_output.temp_path(OutputType::Object, module_name); |
892 | remove(sess, &path); | |
1a4d82fc JJ |
893 | } |
894 | ||
895 | if modules_config.emit_bc && !keep_numbered_bitcode { | |
5bcae85e SL |
896 | let path = crate_output.temp_path(OutputType::Bitcode, module_name); |
897 | remove(sess, &path); | |
1a4d82fc JJ |
898 | } |
899 | } | |
900 | ||
901 | if metadata_config.emit_bc && !user_wants_bitcode { | |
5bcae85e SL |
902 | let path = crate_output.temp_path(OutputType::Bitcode, |
903 | Some(&trans.metadata_module.name[..])); | |
904 | remove(sess, &path); | |
1a4d82fc JJ |
905 | } |
906 | } | |
907 | ||
908 | // We leave the following files around by default: | |
909 | // - crate.o | |
910 | // - crate.metadata.o | |
911 | // - crate.bc | |
912 | // These are used in linking steps and will be cleaned up afterward. | |
913 | ||
914 | // FIXME: time_llvm_passes support - does this use a global context or | |
915 | // something? | |
c34b1796 AL |
916 | if sess.opts.cg.codegen_units == 1 && sess.time_llvm_passes() { |
917 | unsafe { llvm::LLVMRustPrintPassTimings(); } | |
918 | } | |
1a4d82fc JJ |
919 | } |
920 | ||
5bcae85e SL |
921 | fn dump_incremental_data(trans: &CrateTranslation) { |
922 | let mut reuse = 0; | |
923 | for mtrans in trans.modules.iter() { | |
924 | match mtrans.source { | |
925 | ModuleSource::Preexisting(..) => reuse += 1, | |
926 | ModuleSource::Translated(..) => (), | |
927 | } | |
928 | } | |
929 | println!("incremental: re-using {} out of {} modules", reuse, trans.modules.len()); | |
930 | } | |
931 | ||
1a4d82fc JJ |
932 | struct WorkItem { |
933 | mtrans: ModuleTranslation, | |
934 | config: ModuleConfig, | |
5bcae85e | 935 | output_names: OutputFilenames |
1a4d82fc JJ |
936 | } |
937 | ||
938 | fn build_work_item(sess: &Session, | |
939 | mtrans: ModuleTranslation, | |
940 | config: ModuleConfig, | |
5bcae85e | 941 | output_names: OutputFilenames) |
1a4d82fc JJ |
942 | -> WorkItem |
943 | { | |
944 | let mut config = config; | |
945 | config.tm = create_target_machine(sess); | |
5bcae85e SL |
946 | WorkItem { |
947 | mtrans: mtrans, | |
948 | config: config, | |
949 | output_names: output_names | |
950 | } | |
1a4d82fc JJ |
951 | } |
952 | ||
953 | fn execute_work_item(cgcx: &CodegenContext, | |
954 | work_item: WorkItem) { | |
955 | unsafe { | |
5bcae85e SL |
956 | match work_item.mtrans.source { |
957 | ModuleSource::Translated(mllvm) => { | |
958 | debug!("llvm-optimizing {:?}", work_item.mtrans.name); | |
959 | optimize_and_codegen(cgcx, | |
960 | work_item.mtrans, | |
961 | mllvm, | |
962 | work_item.config, | |
963 | work_item.output_names); | |
964 | } | |
965 | ModuleSource::Preexisting(wp) => { | |
9e0c209e SL |
966 | let incr_comp_session_dir = cgcx.incr_comp_session_dir |
967 | .as_ref() | |
968 | .unwrap(); | |
5bcae85e SL |
969 | let name = &work_item.mtrans.name; |
970 | for (kind, saved_file) in wp.saved_files { | |
971 | let obj_out = work_item.output_names.temp_path(kind, Some(name)); | |
9e0c209e SL |
972 | let source_file = in_incr_comp_dir(&incr_comp_session_dir, |
973 | &saved_file); | |
5bcae85e SL |
974 | debug!("copying pre-existing module `{}` from {:?} to {}", |
975 | work_item.mtrans.name, | |
976 | source_file, | |
977 | obj_out.display()); | |
978 | match link_or_copy(&source_file, &obj_out) { | |
9e0c209e | 979 | Ok(_) => { } |
5bcae85e SL |
980 | Err(err) => { |
981 | cgcx.handler.err(&format!("unable to copy {} to {}: {}", | |
982 | source_file.display(), | |
983 | obj_out.display(), | |
984 | err)); | |
985 | } | |
986 | } | |
987 | } | |
988 | } | |
989 | } | |
1a4d82fc JJ |
990 | } |
991 | } | |
992 | ||
993 | fn run_work_singlethreaded(sess: &Session, | |
994 | reachable: &[String], | |
995 | work_items: Vec<WorkItem>) { | |
996 | let cgcx = CodegenContext::new_with_session(sess, reachable); | |
1a4d82fc JJ |
997 | |
998 | // Since we're running single-threaded, we can pass the session to | |
999 | // the proc, allowing `optimize_and_codegen` to perform LTO. | |
62682a34 | 1000 | for work in work_items.into_iter().rev() { |
1a4d82fc JJ |
1001 | execute_work_item(&cgcx, work); |
1002 | } | |
1003 | } | |
1004 | ||
1005 | fn run_work_multithreaded(sess: &Session, | |
1006 | work_items: Vec<WorkItem>, | |
c34b1796 | 1007 | num_workers: usize) { |
5bcae85e SL |
1008 | assert!(num_workers > 0); |
1009 | ||
1a4d82fc JJ |
1010 | // Run some workers to process the work items. |
1011 | let work_items_arc = Arc::new(Mutex::new(work_items)); | |
1012 | let mut diag_emitter = SharedEmitter::new(); | |
1013 | let mut futures = Vec::with_capacity(num_workers); | |
1014 | ||
85aaf69f | 1015 | for i in 0..num_workers { |
1a4d82fc JJ |
1016 | let work_items_arc = work_items_arc.clone(); |
1017 | let diag_emitter = diag_emitter.clone(); | |
9346a6ac | 1018 | let plugin_passes = sess.plugin_llvm_passes.borrow().clone(); |
1a4d82fc JJ |
1019 | let remark = sess.opts.cg.remark.clone(); |
1020 | ||
1021 | let (tx, rx) = channel(); | |
1022 | let mut tx = Some(tx); | |
1023 | futures.push(rx); | |
1024 | ||
9e0c209e | 1025 | let incr_comp_session_dir = sess.incr_comp_session_dir_opt().map(|r| r.clone()); |
5bcae85e | 1026 | |
85aaf69f | 1027 | thread::Builder::new().name(format!("codegen-{}", i)).spawn(move || { |
9cc50fc6 | 1028 | let diag_handler = Handler::with_emitter(true, false, box diag_emitter); |
1a4d82fc JJ |
1029 | |
1030 | // Must construct cgcx inside the proc because it has non-Send | |
1031 | // fields. | |
1032 | let cgcx = CodegenContext { | |
1033 | lto_ctxt: None, | |
1034 | handler: &diag_handler, | |
9346a6ac | 1035 | plugin_passes: plugin_passes, |
1a4d82fc | 1036 | remark: remark, |
b039eaaf | 1037 | worker: i, |
9e0c209e | 1038 | incr_comp_session_dir: incr_comp_session_dir |
1a4d82fc JJ |
1039 | }; |
1040 | ||
1041 | loop { | |
1042 | // Avoid holding the lock for the entire duration of the match. | |
1043 | let maybe_work = work_items_arc.lock().unwrap().pop(); | |
1044 | match maybe_work { | |
1045 | Some(work) => { | |
1046 | execute_work_item(&cgcx, work); | |
1047 | ||
1048 | // Make sure to fail the worker so the main thread can | |
1049 | // tell that there were errors. | |
1050 | cgcx.handler.abort_if_errors(); | |
1051 | } | |
1052 | None => break, | |
1053 | } | |
1054 | } | |
1055 | ||
1056 | tx.take().unwrap().send(()).unwrap(); | |
85aaf69f | 1057 | }).unwrap(); |
1a4d82fc JJ |
1058 | } |
1059 | ||
1060 | let mut panicked = false; | |
85aaf69f | 1061 | for rx in futures { |
1a4d82fc JJ |
1062 | match rx.recv() { |
1063 | Ok(()) => {}, | |
1064 | Err(_) => { | |
1065 | panicked = true; | |
1066 | }, | |
1067 | } | |
1068 | // Display any new diagnostics. | |
9cc50fc6 | 1069 | diag_emitter.dump(sess.diagnostic()); |
1a4d82fc JJ |
1070 | } |
1071 | if panicked { | |
1072 | sess.fatal("aborting due to worker thread panic"); | |
1073 | } | |
1074 | } | |
1075 | ||
1076 | pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) { | |
3157f602 | 1077 | let (pname, mut cmd, _) = get_linker(sess); |
1a4d82fc | 1078 | |
b039eaaf | 1079 | cmd.arg("-c").arg("-o").arg(&outputs.path(OutputType::Object)) |
5bcae85e | 1080 | .arg(&outputs.temp_path(OutputType::Assembly, None)); |
c34b1796 | 1081 | debug!("{:?}", cmd); |
1a4d82fc JJ |
1082 | |
1083 | match cmd.output() { | |
1084 | Ok(prog) => { | |
1085 | if !prog.status.success() { | |
c34b1796 | 1086 | let mut note = prog.stderr.clone(); |
92a42be0 | 1087 | note.extend_from_slice(&prog.stdout); |
9cc50fc6 SL |
1088 | |
1089 | sess.struct_err(&format!("linking with `{}` failed: {}", | |
1090 | pname, | |
1091 | prog.status)) | |
1092 | .note(&format!("{:?}", &cmd)) | |
1093 | .note(str::from_utf8(¬e[..]).unwrap()) | |
1094 | .emit(); | |
1a4d82fc JJ |
1095 | sess.abort_if_errors(); |
1096 | } | |
1097 | }, | |
1098 | Err(e) => { | |
c1a9b12d | 1099 | sess.err(&format!("could not exec the linker `{}`: {}", pname, e)); |
1a4d82fc JJ |
1100 | sess.abort_if_errors(); |
1101 | } | |
1102 | } | |
1103 | } | |
1104 | ||
c1a9b12d SL |
1105 | pub unsafe fn with_llvm_pmb(llmod: ModuleRef, |
1106 | config: &ModuleConfig, | |
1107 | f: &mut FnMut(llvm::PassManagerBuilderRef)) { | |
1a4d82fc JJ |
1108 | // Create the PassManagerBuilder for LLVM. We configure it with |
1109 | // reasonable defaults and prepare it to actually populate the pass | |
1110 | // manager. | |
1111 | let builder = llvm::LLVMPassManagerBuilderCreate(); | |
5bcae85e | 1112 | let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None); |
a7813a04 | 1113 | let opt_size = config.opt_size.unwrap_or(llvm::CodeGenOptSizeNone); |
92a42be0 | 1114 | let inline_threshold = config.inline_threshold; |
62682a34 | 1115 | |
a7813a04 | 1116 | llvm::LLVMRustConfigurePassManagerBuilder(builder, opt_level, |
62682a34 SL |
1117 | config.merge_functions, |
1118 | config.vectorize_slp, | |
1119 | config.vectorize_loop); | |
a7813a04 XL |
1120 | llvm::LLVMPassManagerBuilderSetSizeLevel(builder, opt_size as u32); |
1121 | ||
1122 | if opt_size != llvm::CodeGenOptSizeNone { | |
1123 | llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(builder, 1); | |
1124 | } | |
62682a34 SL |
1125 | |
1126 | llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins); | |
1127 | ||
1128 | // Here we match what clang does (kinda). For O0 we only inline | |
1129 | // always-inline functions (but don't add lifetime intrinsics), at O1 we | |
1130 | // inline with lifetime intrinsics, and O2+ we add an inliner with a | |
1131 | // thresholds copied from clang. | |
a7813a04 | 1132 | match (opt_level, opt_size, inline_threshold) { |
9e0c209e | 1133 | (.., Some(t)) => { |
92a42be0 SL |
1134 | llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32); |
1135 | } | |
9e0c209e | 1136 | (llvm::CodeGenOptLevel::Aggressive, ..) => { |
a7813a04 XL |
1137 | llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275); |
1138 | } | |
1139 | (_, llvm::CodeGenOptSizeDefault, _) => { | |
1140 | llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 75); | |
1141 | } | |
1142 | (_, llvm::CodeGenOptSizeAggressive, _) => { | |
1143 | llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25); | |
1144 | } | |
9e0c209e | 1145 | (llvm::CodeGenOptLevel::None, ..) => { |
1a4d82fc JJ |
1146 | llvm::LLVMRustAddAlwaysInlinePass(builder, false); |
1147 | } | |
9e0c209e | 1148 | (llvm::CodeGenOptLevel::Less, ..) => { |
1a4d82fc JJ |
1149 | llvm::LLVMRustAddAlwaysInlinePass(builder, true); |
1150 | } | |
9e0c209e | 1151 | (llvm::CodeGenOptLevel::Default, ..) => { |
62682a34 | 1152 | llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225); |
1a4d82fc | 1153 | } |
9e0c209e | 1154 | (llvm::CodeGenOptLevel::Other, ..) => { |
5bcae85e SL |
1155 | bug!("CodeGenOptLevel::Other selected") |
1156 | } | |
1a4d82fc | 1157 | } |
1a4d82fc | 1158 | |
c1a9b12d | 1159 | f(builder); |
1a4d82fc | 1160 | llvm::LLVMPassManagerBuilderDispose(builder); |
1a4d82fc | 1161 | } |