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