]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_codegen_ssa/src/base.rs
New upstream version 1.59.0+dfsg1
[rustc.git] / compiler / rustc_codegen_ssa / src / base.rs
1 use crate::back::metadata::create_compressed_metadata_file;
2 use crate::back::write::{
3 compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm,
4 submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen,
5 };
6 use crate::common::{IntPredicate, RealPredicate, TypeKind};
7 use crate::meth;
8 use crate::mir;
9 use crate::mir::operand::OperandValue;
10 use crate::mir::place::PlaceRef;
11 use crate::traits::*;
12 use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind};
13
14 use rustc_attr as attr;
15 use rustc_data_structures::fx::FxHashMap;
16 use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
17 use rustc_data_structures::sync::{par_iter, ParallelIterator};
18 use rustc_hir as hir;
19 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
20 use rustc_hir::lang_items::LangItem;
21 use rustc_index::vec::Idx;
22 use rustc_metadata::EncodedMetadata;
23 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
24 use rustc_middle::middle::exported_symbols;
25 use rustc_middle::middle::lang_items;
26 use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
27 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
28 use rustc_middle::ty::query::Providers;
29 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
30 use rustc_session::cgu_reuse_tracker::CguReuse;
31 use rustc_session::config::{self, EntryFnType, OutputType};
32 use rustc_session::Session;
33 use rustc_span::symbol::sym;
34 use rustc_target::abi::{Align, VariantIdx};
35
36 use std::convert::TryFrom;
37 use std::ops::{Deref, DerefMut};
38 use std::time::{Duration, Instant};
39
40 use itertools::Itertools;
41
42 pub fn bin_op_to_icmp_predicate(op: hir::BinOpKind, signed: bool) -> IntPredicate {
43 match op {
44 hir::BinOpKind::Eq => IntPredicate::IntEQ,
45 hir::BinOpKind::Ne => IntPredicate::IntNE,
46 hir::BinOpKind::Lt => {
47 if signed {
48 IntPredicate::IntSLT
49 } else {
50 IntPredicate::IntULT
51 }
52 }
53 hir::BinOpKind::Le => {
54 if signed {
55 IntPredicate::IntSLE
56 } else {
57 IntPredicate::IntULE
58 }
59 }
60 hir::BinOpKind::Gt => {
61 if signed {
62 IntPredicate::IntSGT
63 } else {
64 IntPredicate::IntUGT
65 }
66 }
67 hir::BinOpKind::Ge => {
68 if signed {
69 IntPredicate::IntSGE
70 } else {
71 IntPredicate::IntUGE
72 }
73 }
74 op => bug!(
75 "comparison_op_to_icmp_predicate: expected comparison operator, \
76 found {:?}",
77 op
78 ),
79 }
80 }
81
82 pub fn bin_op_to_fcmp_predicate(op: hir::BinOpKind) -> RealPredicate {
83 match op {
84 hir::BinOpKind::Eq => RealPredicate::RealOEQ,
85 hir::BinOpKind::Ne => RealPredicate::RealUNE,
86 hir::BinOpKind::Lt => RealPredicate::RealOLT,
87 hir::BinOpKind::Le => RealPredicate::RealOLE,
88 hir::BinOpKind::Gt => RealPredicate::RealOGT,
89 hir::BinOpKind::Ge => RealPredicate::RealOGE,
90 op => {
91 bug!(
92 "comparison_op_to_fcmp_predicate: expected comparison operator, \
93 found {:?}",
94 op
95 );
96 }
97 }
98 }
99
100 pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
101 bx: &mut Bx,
102 lhs: Bx::Value,
103 rhs: Bx::Value,
104 t: Ty<'tcx>,
105 ret_ty: Bx::Type,
106 op: hir::BinOpKind,
107 ) -> Bx::Value {
108 let signed = match t.kind() {
109 ty::Float(_) => {
110 let cmp = bin_op_to_fcmp_predicate(op);
111 let cmp = bx.fcmp(cmp, lhs, rhs);
112 return bx.sext(cmp, ret_ty);
113 }
114 ty::Uint(_) => false,
115 ty::Int(_) => true,
116 _ => bug!("compare_simd_types: invalid SIMD type"),
117 };
118
119 let cmp = bin_op_to_icmp_predicate(op, signed);
120 let cmp = bx.icmp(cmp, lhs, rhs);
121 // LLVM outputs an `< size x i1 >`, so we need to perform a sign extension
122 // to get the correctly sized type. This will compile to a single instruction
123 // once the IR is converted to assembly if the SIMD instruction is supported
124 // by the target architecture.
125 bx.sext(cmp, ret_ty)
126 }
127
128 /// Retrieves the information we are losing (making dynamic) in an unsizing
129 /// adjustment.
130 ///
131 /// The `old_info` argument is a bit odd. It is intended for use in an upcast,
132 /// where the new vtable for an object will be derived from the old one.
133 pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
134 bx: &mut Bx,
135 source: Ty<'tcx>,
136 target: Ty<'tcx>,
137 old_info: Option<Bx::Value>,
138 ) -> Bx::Value {
139 let cx = bx.cx();
140 let (source, target) =
141 cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, bx.param_env());
142 match (source.kind(), target.kind()) {
143 (&ty::Array(_, len), &ty::Slice(_)) => {
144 cx.const_usize(len.eval_usize(cx.tcx(), ty::ParamEnv::reveal_all()))
145 }
146 (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
147 let old_info =
148 old_info.expect("unsized_info: missing old info for trait upcasting coercion");
149 if data_a.principal_def_id() == data_b.principal_def_id() {
150 return old_info;
151 }
152
153 // trait upcasting coercion
154
155 let vptr_entry_idx =
156 cx.tcx().vtable_trait_upcasting_coercion_new_vptr_slot((source, target));
157
158 if let Some(entry_idx) = vptr_entry_idx {
159 let ptr_ty = cx.type_i8p();
160 let ptr_align = cx.tcx().data_layout.pointer_align.abi;
161 let llvtable = bx.pointercast(old_info, bx.type_ptr_to(ptr_ty));
162 let gep = bx.inbounds_gep(
163 ptr_ty,
164 llvtable,
165 &[bx.const_usize(u64::try_from(entry_idx).unwrap())],
166 );
167 let new_vptr = bx.load(ptr_ty, gep, ptr_align);
168 bx.nonnull_metadata(new_vptr);
169 // Vtable loads are invariant.
170 bx.set_invariant_load(new_vptr);
171 new_vptr
172 } else {
173 old_info
174 }
175 }
176 (_, &ty::Dynamic(ref data, ..)) => {
177 let vtable_ptr_ty = cx.scalar_pair_element_backend_type(
178 cx.layout_of(cx.tcx().mk_mut_ptr(target)),
179 1,
180 true,
181 );
182 cx.const_ptrcast(meth::get_vtable(cx, source, data.principal()), vtable_ptr_ty)
183 }
184 _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
185 }
186 }
187
188 /// Coerces `src` to `dst_ty`. `src_ty` must be a pointer.
189 pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
190 bx: &mut Bx,
191 src: Bx::Value,
192 src_ty: Ty<'tcx>,
193 dst_ty: Ty<'tcx>,
194 old_info: Option<Bx::Value>,
195 ) -> (Bx::Value, Bx::Value) {
196 debug!("unsize_ptr: {:?} => {:?}", src_ty, dst_ty);
197 match (src_ty.kind(), dst_ty.kind()) {
198 (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(ty::TypeAndMut { ty: b, .. }))
199 | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
200 assert_eq!(bx.cx().type_is_sized(a), old_info.is_none());
201 let ptr_ty = bx.cx().type_ptr_to(bx.cx().backend_type(bx.cx().layout_of(b)));
202 (bx.pointercast(src, ptr_ty), unsized_info(bx, a, b, old_info))
203 }
204 (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
205 assert_eq!(def_a, def_b);
206 let src_layout = bx.cx().layout_of(src_ty);
207 let dst_layout = bx.cx().layout_of(dst_ty);
208 if src_ty == dst_ty {
209 return (src, old_info.unwrap());
210 }
211 let mut result = None;
212 for i in 0..src_layout.fields.count() {
213 let src_f = src_layout.field(bx.cx(), i);
214 assert_eq!(src_layout.fields.offset(i).bytes(), 0);
215 assert_eq!(dst_layout.fields.offset(i).bytes(), 0);
216 if src_f.is_zst() {
217 continue;
218 }
219 assert_eq!(src_layout.size, src_f.size);
220
221 let dst_f = dst_layout.field(bx.cx(), i);
222 assert_ne!(src_f.ty, dst_f.ty);
223 assert_eq!(result, None);
224 result = Some(unsize_ptr(bx, src, src_f.ty, dst_f.ty, old_info));
225 }
226 let (lldata, llextra) = result.unwrap();
227 let lldata_ty = bx.cx().scalar_pair_element_backend_type(dst_layout, 0, true);
228 let llextra_ty = bx.cx().scalar_pair_element_backend_type(dst_layout, 1, true);
229 // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
230 (bx.bitcast(lldata, lldata_ty), bx.bitcast(llextra, llextra_ty))
231 }
232 _ => bug!("unsize_ptr: called on bad types"),
233 }
234 }
235
236 /// Coerces `src`, which is a reference to a value of type `src_ty`,
237 /// to a value of type `dst_ty`, and stores the result in `dst`.
238 pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
239 bx: &mut Bx,
240 src: PlaceRef<'tcx, Bx::Value>,
241 dst: PlaceRef<'tcx, Bx::Value>,
242 ) {
243 let src_ty = src.layout.ty;
244 let dst_ty = dst.layout.ty;
245 match (src_ty.kind(), dst_ty.kind()) {
246 (&ty::Ref(..), &ty::Ref(..) | &ty::RawPtr(..)) | (&ty::RawPtr(..), &ty::RawPtr(..)) => {
247 let (base, info) = match bx.load_operand(src).val {
248 OperandValue::Pair(base, info) => unsize_ptr(bx, base, src_ty, dst_ty, Some(info)),
249 OperandValue::Immediate(base) => unsize_ptr(bx, base, src_ty, dst_ty, None),
250 OperandValue::Ref(..) => bug!(),
251 };
252 OperandValue::Pair(base, info).store(bx, dst);
253 }
254
255 (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
256 assert_eq!(def_a, def_b);
257
258 for i in 0..def_a.variants[VariantIdx::new(0)].fields.len() {
259 let src_f = src.project_field(bx, i);
260 let dst_f = dst.project_field(bx, i);
261
262 if dst_f.layout.is_zst() {
263 continue;
264 }
265
266 if src_f.layout.ty == dst_f.layout.ty {
267 memcpy_ty(
268 bx,
269 dst_f.llval,
270 dst_f.align,
271 src_f.llval,
272 src_f.align,
273 src_f.layout,
274 MemFlags::empty(),
275 );
276 } else {
277 coerce_unsized_into(bx, src_f, dst_f);
278 }
279 }
280 }
281 _ => bug!("coerce_unsized_into: invalid coercion {:?} -> {:?}", src_ty, dst_ty,),
282 }
283 }
284
285 pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
286 bx: &mut Bx,
287 op: hir::BinOpKind,
288 lhs: Bx::Value,
289 rhs: Bx::Value,
290 ) -> Bx::Value {
291 cast_shift_rhs(bx, op, lhs, rhs)
292 }
293
294 fn cast_shift_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
295 bx: &mut Bx,
296 op: hir::BinOpKind,
297 lhs: Bx::Value,
298 rhs: Bx::Value,
299 ) -> Bx::Value {
300 // Shifts may have any size int on the rhs
301 if op.is_shift() {
302 let mut rhs_llty = bx.cx().val_ty(rhs);
303 let mut lhs_llty = bx.cx().val_ty(lhs);
304 if bx.cx().type_kind(rhs_llty) == TypeKind::Vector {
305 rhs_llty = bx.cx().element_type(rhs_llty)
306 }
307 if bx.cx().type_kind(lhs_llty) == TypeKind::Vector {
308 lhs_llty = bx.cx().element_type(lhs_llty)
309 }
310 let rhs_sz = bx.cx().int_width(rhs_llty);
311 let lhs_sz = bx.cx().int_width(lhs_llty);
312 if lhs_sz < rhs_sz {
313 bx.trunc(rhs, lhs_llty)
314 } else if lhs_sz > rhs_sz {
315 // FIXME (#1877: If in the future shifting by negative
316 // values is no longer undefined then this is wrong.
317 bx.zext(rhs, lhs_llty)
318 } else {
319 rhs
320 }
321 } else {
322 rhs
323 }
324 }
325
326 /// Returns `true` if this session's target will use SEH-based unwinding.
327 ///
328 /// This is only true for MSVC targets, and even then the 64-bit MSVC target
329 /// currently uses SEH-ish unwinding with DWARF info tables to the side (same as
330 /// 64-bit MinGW) instead of "full SEH".
331 pub fn wants_msvc_seh(sess: &Session) -> bool {
332 sess.target.is_like_msvc
333 }
334
335 pub fn memcpy_ty<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
336 bx: &mut Bx,
337 dst: Bx::Value,
338 dst_align: Align,
339 src: Bx::Value,
340 src_align: Align,
341 layout: TyAndLayout<'tcx>,
342 flags: MemFlags,
343 ) {
344 let size = layout.size.bytes();
345 if size == 0 {
346 return;
347 }
348
349 bx.memcpy(dst, dst_align, src, src_align, bx.cx().const_usize(size), flags);
350 }
351
352 pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
353 cx: &'a Bx::CodegenCx,
354 instance: Instance<'tcx>,
355 ) {
356 // this is an info! to allow collecting monomorphization statistics
357 // and to allow finding the last function before LLVM aborts from
358 // release builds.
359 info!("codegen_instance({})", instance);
360
361 mir::codegen_mir::<Bx>(cx, instance);
362 }
363
364 /// Creates the `main` function which will initialize the rust runtime and call
365 /// users main function.
366 pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
367 cx: &'a Bx::CodegenCx,
368 ) -> Option<Bx::Function> {
369 let (main_def_id, entry_type) = cx.tcx().entry_fn(())?;
370 let main_is_local = main_def_id.is_local();
371 let instance = Instance::mono(cx.tcx(), main_def_id);
372
373 if main_is_local {
374 // We want to create the wrapper in the same codegen unit as Rust's main
375 // function.
376 if !cx.codegen_unit().contains_item(&MonoItem::Fn(instance)) {
377 return None;
378 }
379 } else if !cx.codegen_unit().is_primary() {
380 // We want to create the wrapper only when the codegen unit is the primary one
381 return None;
382 }
383
384 let main_llfn = cx.get_fn_addr(instance);
385
386 let use_start_lang_item = EntryFnType::Start != entry_type;
387 let entry_fn = create_entry_fn::<Bx>(cx, main_llfn, main_def_id, use_start_lang_item);
388 return Some(entry_fn);
389
390 fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
391 cx: &'a Bx::CodegenCx,
392 rust_main: Bx::Value,
393 rust_main_def_id: DefId,
394 use_start_lang_item: bool,
395 ) -> Bx::Function {
396 // The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
397 // depending on whether the target needs `argc` and `argv` to be passed in.
398 let llfty = if cx.sess().target.main_needs_argc_argv {
399 cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int())
400 } else {
401 cx.type_func(&[], cx.type_int())
402 };
403
404 let main_ret_ty = cx.tcx().fn_sig(rust_main_def_id).output();
405 // Given that `main()` has no arguments,
406 // then its return type cannot have
407 // late-bound regions, since late-bound
408 // regions must appear in the argument
409 // listing.
410 let main_ret_ty = cx.tcx().erase_regions(main_ret_ty.no_bound_vars().unwrap());
411
412 let llfn = match cx.declare_c_main(llfty) {
413 Some(llfn) => llfn,
414 None => {
415 // FIXME: We should be smart and show a better diagnostic here.
416 let span = cx.tcx().def_span(rust_main_def_id);
417 cx.sess()
418 .struct_span_err(span, "entry symbol `main` declared multiple times")
419 .help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead")
420 .emit();
421 cx.sess().abort_if_errors();
422 bug!();
423 }
424 };
425
426 // `main` should respect same config for frame pointer elimination as rest of code
427 cx.set_frame_pointer_type(llfn);
428 cx.apply_target_cpu_attr(llfn);
429
430 let llbb = Bx::append_block(&cx, llfn, "top");
431 let mut bx = Bx::build(&cx, llbb);
432
433 bx.insert_reference_to_gdb_debug_scripts_section_global();
434
435 let isize_ty = cx.type_isize();
436 let i8pp_ty = cx.type_ptr_to(cx.type_i8p());
437 let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx);
438
439 let (start_fn, start_ty, args) = if use_start_lang_item {
440 let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None);
441 let start_fn = cx.get_fn_addr(
442 ty::Instance::resolve(
443 cx.tcx(),
444 ty::ParamEnv::reveal_all(),
445 start_def_id,
446 cx.tcx().intern_substs(&[main_ret_ty.into()]),
447 )
448 .unwrap()
449 .unwrap(),
450 );
451 let start_ty = cx.type_func(&[cx.val_ty(rust_main), isize_ty, i8pp_ty], isize_ty);
452 (start_fn, start_ty, vec![rust_main, arg_argc, arg_argv])
453 } else {
454 debug!("using user-defined start fn");
455 let start_ty = cx.type_func(&[isize_ty, i8pp_ty], isize_ty);
456 (rust_main, start_ty, vec![arg_argc, arg_argv])
457 };
458
459 let result = bx.call(start_ty, start_fn, &args, None);
460 let cast = bx.intcast(result, cx.type_int(), true);
461 bx.ret(cast);
462
463 llfn
464 }
465 }
466
467 /// Obtain the `argc` and `argv` values to pass to the rust start function.
468 fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
469 cx: &'a Bx::CodegenCx,
470 bx: &mut Bx,
471 ) -> (Bx::Value, Bx::Value) {
472 if cx.sess().target.main_needs_argc_argv {
473 // Params from native `main()` used as args for rust start function
474 let param_argc = bx.get_param(0);
475 let param_argv = bx.get_param(1);
476 let arg_argc = bx.intcast(param_argc, cx.type_isize(), true);
477 let arg_argv = param_argv;
478 (arg_argc, arg_argv)
479 } else {
480 // The Rust start function doesn't need `argc` and `argv`, so just pass zeros.
481 let arg_argc = bx.const_int(cx.type_int(), 0);
482 let arg_argv = bx.const_null(cx.type_ptr_to(cx.type_i8p()));
483 (arg_argc, arg_argv)
484 }
485 }
486
487 pub fn codegen_crate<B: ExtraBackendMethods>(
488 backend: B,
489 tcx: TyCtxt<'_>,
490 target_cpu: String,
491 metadata: EncodedMetadata,
492 need_metadata_module: bool,
493 ) -> OngoingCodegen<B> {
494 // Skip crate items and just output metadata in -Z no-codegen mode.
495 if tcx.sess.opts.debugging_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() {
496 let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, metadata, None, 1);
497
498 ongoing_codegen.codegen_finished(tcx);
499
500 ongoing_codegen.check_for_errors(tcx.sess);
501
502 return ongoing_codegen;
503 }
504
505 let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
506
507 // Run the monomorphization collector and partition the collected items into
508 // codegen units.
509 let codegen_units = tcx.collect_and_partition_mono_items(()).1;
510
511 // Force all codegen_unit queries so they are already either red or green
512 // when compile_codegen_unit accesses them. We are not able to re-execute
513 // the codegen_unit query from just the DepNode, so an unknown color would
514 // lead to having to re-execute compile_codegen_unit, possibly
515 // unnecessarily.
516 if tcx.dep_graph.is_fully_enabled() {
517 for cgu in codegen_units {
518 tcx.ensure().codegen_unit(cgu.name());
519 }
520 }
521
522 let metadata_module = if need_metadata_module {
523 // Emit compressed metadata object.
524 let metadata_cgu_name =
525 cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")).to_string();
526 tcx.sess.time("write_compressed_metadata", || {
527 let file_name =
528 tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
529 let data = create_compressed_metadata_file(
530 tcx.sess,
531 &metadata,
532 &exported_symbols::metadata_symbol_name(tcx),
533 );
534 if let Err(err) = std::fs::write(&file_name, data) {
535 tcx.sess.fatal(&format!("error writing metadata object file: {}", err));
536 }
537 Some(CompiledModule {
538 name: metadata_cgu_name,
539 kind: ModuleKind::Metadata,
540 object: Some(file_name),
541 dwarf_object: None,
542 bytecode: None,
543 })
544 })
545 } else {
546 None
547 };
548
549 let ongoing_codegen = start_async_codegen(
550 backend.clone(),
551 tcx,
552 target_cpu,
553 metadata,
554 metadata_module,
555 codegen_units.len(),
556 );
557 let ongoing_codegen = AbortCodegenOnDrop::<B>(Some(ongoing_codegen));
558
559 // Codegen an allocator shim, if necessary.
560 //
561 // If the crate doesn't have an `allocator_kind` set then there's definitely
562 // no shim to generate. Otherwise we also check our dependency graph for all
563 // our output crate types. If anything there looks like its a `Dynamic`
564 // linkage, then it's already got an allocator shim and we'll be using that
565 // one instead. If nothing exists then it's our job to generate the
566 // allocator!
567 let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| {
568 use rustc_middle::middle::dependency_format::Linkage;
569 list.iter().any(|&linkage| linkage == Linkage::Dynamic)
570 });
571 let allocator_module = if any_dynamic_crate {
572 None
573 } else if let Some(kind) = tcx.allocator_kind(()) {
574 let llmod_id =
575 cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
576 let mut module_llvm = backend.new_metadata(tcx, &llmod_id);
577 tcx.sess.time("write_allocator_module", || {
578 backend.codegen_allocator(
579 tcx,
580 &mut module_llvm,
581 &llmod_id,
582 kind,
583 tcx.lang_items().oom().is_some(),
584 )
585 });
586
587 Some(ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator })
588 } else {
589 None
590 };
591
592 if let Some(allocator_module) = allocator_module {
593 ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, allocator_module);
594 }
595
596 // For better throughput during parallel processing by LLVM, we used to sort
597 // CGUs largest to smallest. This would lead to better thread utilization
598 // by, for example, preventing a large CGU from being processed last and
599 // having only one LLVM thread working while the rest remained idle.
600 //
601 // However, this strategy would lead to high memory usage, as it meant the
602 // LLVM-IR for all of the largest CGUs would be resident in memory at once.
603 //
604 // Instead, we can compromise by ordering CGUs such that the largest and
605 // smallest are first, second largest and smallest are next, etc. If there
606 // are large size variations, this can reduce memory usage significantly.
607 let codegen_units: Vec<_> = {
608 let mut sorted_cgus = codegen_units.iter().collect::<Vec<_>>();
609 sorted_cgus.sort_by_cached_key(|cgu| cgu.size_estimate());
610
611 let (first_half, second_half) = sorted_cgus.split_at(sorted_cgus.len() / 2);
612 second_half.iter().rev().interleave(first_half).copied().collect()
613 };
614
615 // The non-parallel compiler can only translate codegen units to LLVM IR
616 // on a single thread, leading to a staircase effect where the N LLVM
617 // threads have to wait on the single codegen threads to generate work
618 // for them. The parallel compiler does not have this restriction, so
619 // we can pre-load the LLVM queue in parallel before handing off
620 // coordination to the OnGoingCodegen scheduler.
621 //
622 // This likely is a temporary measure. Once we don't have to support the
623 // non-parallel compiler anymore, we can compile CGUs end-to-end in
624 // parallel and get rid of the complicated scheduling logic.
625 let pre_compile_cgus = |cgu_reuse: &[CguReuse]| {
626 if cfg!(parallel_compiler) {
627 tcx.sess.time("compile_first_CGU_batch", || {
628 // Try to find one CGU to compile per thread.
629 let cgus: Vec<_> = cgu_reuse
630 .iter()
631 .enumerate()
632 .filter(|&(_, reuse)| reuse == &CguReuse::No)
633 .take(tcx.sess.threads())
634 .collect();
635
636 // Compile the found CGUs in parallel.
637 let start_time = Instant::now();
638
639 let pre_compiled_cgus = par_iter(cgus)
640 .map(|(i, _)| {
641 let module = backend.compile_codegen_unit(tcx, codegen_units[i].name());
642 (i, module)
643 })
644 .collect();
645
646 (pre_compiled_cgus, start_time.elapsed())
647 })
648 } else {
649 (FxHashMap::default(), Duration::new(0, 0))
650 }
651 };
652
653 let mut cgu_reuse = Vec::new();
654 let mut pre_compiled_cgus: Option<FxHashMap<usize, _>> = None;
655 let mut total_codegen_time = Duration::new(0, 0);
656 let start_rss = tcx.sess.time_passes().then(|| get_resident_set_size());
657
658 for (i, cgu) in codegen_units.iter().enumerate() {
659 ongoing_codegen.wait_for_signal_to_codegen_item();
660 ongoing_codegen.check_for_errors(tcx.sess);
661
662 // Do some setup work in the first iteration
663 if pre_compiled_cgus.is_none() {
664 // Calculate the CGU reuse
665 cgu_reuse = tcx.sess.time("find_cgu_reuse", || {
666 codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect()
667 });
668 // Pre compile some CGUs
669 let (compiled_cgus, codegen_time) = pre_compile_cgus(&cgu_reuse);
670 pre_compiled_cgus = Some(compiled_cgus);
671 total_codegen_time += codegen_time;
672 }
673
674 let cgu_reuse = cgu_reuse[i];
675 tcx.sess.cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse);
676
677 match cgu_reuse {
678 CguReuse::No => {
679 let (module, cost) =
680 if let Some(cgu) = pre_compiled_cgus.as_mut().unwrap().remove(&i) {
681 cgu
682 } else {
683 let start_time = Instant::now();
684 let module = backend.compile_codegen_unit(tcx, cgu.name());
685 total_codegen_time += start_time.elapsed();
686 module
687 };
688 // This will unwind if there are errors, which triggers our `AbortCodegenOnDrop`
689 // guard. Unfortunately, just skipping the `submit_codegened_module_to_llvm` makes
690 // compilation hang on post-monomorphization errors.
691 tcx.sess.abort_if_errors();
692
693 submit_codegened_module_to_llvm(
694 &backend,
695 &ongoing_codegen.coordinator_send,
696 module,
697 cost,
698 );
699 false
700 }
701 CguReuse::PreLto => {
702 submit_pre_lto_module_to_llvm(
703 &backend,
704 tcx,
705 &ongoing_codegen.coordinator_send,
706 CachedModuleCodegen {
707 name: cgu.name().to_string(),
708 source: cgu.work_product(tcx),
709 },
710 );
711 true
712 }
713 CguReuse::PostLto => {
714 submit_post_lto_module_to_llvm(
715 &backend,
716 &ongoing_codegen.coordinator_send,
717 CachedModuleCodegen {
718 name: cgu.name().to_string(),
719 source: cgu.work_product(tcx),
720 },
721 );
722 true
723 }
724 };
725 }
726
727 ongoing_codegen.codegen_finished(tcx);
728
729 // Since the main thread is sometimes blocked during codegen, we keep track
730 // -Ztime-passes output manually.
731 if tcx.sess.time_passes() {
732 let end_rss = get_resident_set_size();
733
734 print_time_passes_entry(
735 "codegen_to_LLVM_IR",
736 total_codegen_time,
737 start_rss.unwrap(),
738 end_rss,
739 );
740 }
741
742 ongoing_codegen.check_for_errors(tcx.sess);
743
744 ongoing_codegen.into_inner()
745 }
746
747 /// A curious wrapper structure whose only purpose is to call `codegen_aborted`
748 /// when it's dropped abnormally.
749 ///
750 /// In the process of working on rust-lang/rust#55238 a mysterious segfault was
751 /// stumbled upon. The segfault was never reproduced locally, but it was
752 /// suspected to be related to the fact that codegen worker threads were
753 /// sticking around by the time the main thread was exiting, causing issues.
754 ///
755 /// This structure is an attempt to fix that issue where the `codegen_aborted`
756 /// message will block until all workers have finished. This should ensure that
757 /// even if the main codegen thread panics we'll wait for pending work to
758 /// complete before returning from the main thread, hopefully avoiding
759 /// segfaults.
760 ///
761 /// If you see this comment in the code, then it means that this workaround
762 /// worked! We may yet one day track down the mysterious cause of that
763 /// segfault...
764 struct AbortCodegenOnDrop<B: ExtraBackendMethods>(Option<OngoingCodegen<B>>);
765
766 impl<B: ExtraBackendMethods> AbortCodegenOnDrop<B> {
767 fn into_inner(mut self) -> OngoingCodegen<B> {
768 self.0.take().unwrap()
769 }
770 }
771
772 impl<B: ExtraBackendMethods> Deref for AbortCodegenOnDrop<B> {
773 type Target = OngoingCodegen<B>;
774
775 fn deref(&self) -> &OngoingCodegen<B> {
776 self.0.as_ref().unwrap()
777 }
778 }
779
780 impl<B: ExtraBackendMethods> DerefMut for AbortCodegenOnDrop<B> {
781 fn deref_mut(&mut self) -> &mut OngoingCodegen<B> {
782 self.0.as_mut().unwrap()
783 }
784 }
785
786 impl<B: ExtraBackendMethods> Drop for AbortCodegenOnDrop<B> {
787 fn drop(&mut self) {
788 if let Some(codegen) = self.0.take() {
789 codegen.codegen_aborted();
790 }
791 }
792 }
793
794 impl CrateInfo {
795 pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
796 let exported_symbols = tcx
797 .sess
798 .crate_types()
799 .iter()
800 .map(|&c| (c, crate::back::linker::exported_symbols(tcx, c)))
801 .collect();
802 let local_crate_name = tcx.crate_name(LOCAL_CRATE);
803 let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
804 let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
805 let windows_subsystem = subsystem.map(|subsystem| {
806 if subsystem != sym::windows && subsystem != sym::console {
807 tcx.sess.fatal(&format!(
808 "invalid windows subsystem `{}`, only \
809 `windows` and `console` are allowed",
810 subsystem
811 ));
812 }
813 subsystem.to_string()
814 });
815
816 // This list is used when generating the command line to pass through to
817 // system linker. The linker expects undefined symbols on the left of the
818 // command line to be defined in libraries on the right, not the other way
819 // around. For more info, see some comments in the add_used_library function
820 // below.
821 //
822 // In order to get this left-to-right dependency ordering, we use the reverse
823 // postorder of all crates putting the leaves at the right-most positions.
824 let used_crates = tcx
825 .postorder_cnums(())
826 .iter()
827 .rev()
828 .copied()
829 .filter(|&cnum| !tcx.dep_kind(cnum).macros_only())
830 .collect();
831
832 let mut info = CrateInfo {
833 target_cpu,
834 exported_symbols,
835 local_crate_name,
836 compiler_builtins: None,
837 profiler_runtime: None,
838 is_no_builtins: Default::default(),
839 native_libraries: Default::default(),
840 used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(),
841 crate_name: Default::default(),
842 used_crates,
843 used_crate_source: Default::default(),
844 lang_item_to_crate: Default::default(),
845 missing_lang_items: Default::default(),
846 dependency_formats: tcx.dependency_formats(()),
847 windows_subsystem,
848 };
849 let lang_items = tcx.lang_items();
850
851 let crates = tcx.crates(());
852
853 let n_crates = crates.len();
854 info.native_libraries.reserve(n_crates);
855 info.crate_name.reserve(n_crates);
856 info.used_crate_source.reserve(n_crates);
857 info.missing_lang_items.reserve(n_crates);
858
859 for &cnum in crates.iter() {
860 info.native_libraries
861 .insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect());
862 info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string());
863 info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum));
864 if tcx.is_compiler_builtins(cnum) {
865 info.compiler_builtins = Some(cnum);
866 }
867 if tcx.is_profiler_runtime(cnum) {
868 info.profiler_runtime = Some(cnum);
869 }
870 if tcx.is_no_builtins(cnum) {
871 info.is_no_builtins.insert(cnum);
872 }
873 let missing = tcx.missing_lang_items(cnum);
874 for &item in missing.iter() {
875 if let Ok(id) = lang_items.require(item) {
876 info.lang_item_to_crate.insert(item, id.krate);
877 }
878 }
879
880 // No need to look for lang items that don't actually need to exist.
881 let missing =
882 missing.iter().cloned().filter(|&l| lang_items::required(tcx, l)).collect();
883 info.missing_lang_items.insert(cnum, missing);
884 }
885
886 info
887 }
888 }
889
890 pub fn provide(providers: &mut Providers) {
891 providers.backend_optimization_level = |tcx, cratenum| {
892 let for_speed = match tcx.sess.opts.optimize {
893 // If globally no optimisation is done, #[optimize] has no effect.
894 //
895 // This is done because if we ended up "upgrading" to `-O2` here, we’d populate the
896 // pass manager and it is likely that some module-wide passes (such as inliner or
897 // cross-function constant propagation) would ignore the `optnone` annotation we put
898 // on the functions, thus necessarily involving these functions into optimisations.
899 config::OptLevel::No => return config::OptLevel::No,
900 // If globally optimise-speed is already specified, just use that level.
901 config::OptLevel::Less => return config::OptLevel::Less,
902 config::OptLevel::Default => return config::OptLevel::Default,
903 config::OptLevel::Aggressive => return config::OptLevel::Aggressive,
904 // If globally optimize-for-size has been requested, use -O2 instead (if optimize(size)
905 // are present).
906 config::OptLevel::Size => config::OptLevel::Default,
907 config::OptLevel::SizeMin => config::OptLevel::Default,
908 };
909
910 let (defids, _) = tcx.collect_and_partition_mono_items(cratenum);
911 for id in &*defids {
912 let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id);
913 match optimize {
914 attr::OptimizeAttr::None => continue,
915 attr::OptimizeAttr::Size => continue,
916 attr::OptimizeAttr::Speed => {
917 return for_speed;
918 }
919 }
920 }
921 tcx.sess.opts.optimize
922 };
923 }
924
925 fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse {
926 if !tcx.dep_graph.is_fully_enabled() {
927 return CguReuse::No;
928 }
929
930 let work_product_id = &cgu.work_product_id();
931 if tcx.dep_graph.previous_work_product(work_product_id).is_none() {
932 // We don't have anything cached for this CGU. This can happen
933 // if the CGU did not exist in the previous session.
934 return CguReuse::No;
935 }
936
937 // Try to mark the CGU as green. If it we can do so, it means that nothing
938 // affecting the LLVM module has changed and we can re-use a cached version.
939 // If we compile with any kind of LTO, this means we can re-use the bitcode
940 // of the Pre-LTO stage (possibly also the Post-LTO version but we'll only
941 // know that later). If we are not doing LTO, there is only one optimized
942 // version of each module, so we re-use that.
943 let dep_node = cgu.codegen_dep_node(tcx);
944 assert!(
945 !tcx.dep_graph.dep_node_exists(&dep_node),
946 "CompileCodegenUnit dep-node for CGU `{}` already exists before marking.",
947 cgu.name()
948 );
949
950 if tcx.try_mark_green(&dep_node) {
951 // We can re-use either the pre- or the post-thinlto state. If no LTO is
952 // being performed then we can use post-LTO artifacts, otherwise we must
953 // reuse pre-LTO artifacts
954 match compute_per_cgu_lto_type(
955 &tcx.sess.lto(),
956 &tcx.sess.opts,
957 &tcx.sess.crate_types(),
958 ModuleKind::Regular,
959 ) {
960 ComputedLtoType::No => CguReuse::PostLto,
961 _ => CguReuse::PreLto,
962 }
963 } else {
964 CguReuse::No
965 }
966 }