2015-02-28 21:53:12 +00:00
|
|
|
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
2012-12-04 00:48:01 +00:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
2016-02-15 20:41:16 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
//! Codegen the completed AST to the LLVM IR.
|
2015-02-28 21:53:12 +00:00
|
|
|
//!
|
2018-05-08 13:10:16 +00:00
|
|
|
//! Some functions here, such as codegen_block and codegen_expr, return a value --
|
|
|
|
//! the result of the codegen to LLVM -- while others, such as codegen_fn
|
|
|
|
//! and mono_item, are called only for the side effect of adding a
|
2015-02-28 21:53:12 +00:00
|
|
|
//! particular definition to the LLVM IR output we're producing.
|
|
|
|
//!
|
2018-05-08 13:10:16 +00:00
|
|
|
//! Hopefully useful general knowledge about codegen:
|
2015-02-28 21:53:12 +00:00
|
|
|
//!
|
2018-07-10 10:28:39 +00:00
|
|
|
//! * There's no way to find out the Ty type of a Value. Doing so
|
2015-02-28 21:53:12 +00:00
|
|
|
//! would be "trying to get the eggs out of an omelette" (credit:
|
2018-07-02 14:52:53 +00:00
|
|
|
//! pcwalton). You can, instead, find out its llvm::Type by calling val_ty,
|
|
|
|
//! but one llvm::Type corresponds to many `Ty`s; for instance, tup(int, int,
|
|
|
|
//! int) and rec(x=int, y=int, z=int) will have the same llvm::Type.
|
2011-12-14 00:25:51 +00:00
|
|
|
|
2016-07-21 16:49:59 +00:00
|
|
|
use super::ModuleLlvm;
|
|
|
|
use super::ModuleSource;
|
2018-05-08 13:10:16 +00:00
|
|
|
use super::ModuleCodegen;
|
2017-07-25 15:26:24 +00:00
|
|
|
use super::ModuleKind;
|
2014-11-27 12:21:26 +00:00
|
|
|
|
2017-09-21 17:40:50 +00:00
|
|
|
use abi;
|
2018-07-16 06:58:56 +00:00
|
|
|
use back::link;
|
2018-06-27 14:57:25 +00:00
|
|
|
use back::write::{self, OngoingCodegen};
|
2018-07-10 10:28:39 +00:00
|
|
|
use llvm::{self, TypeKind, get_param};
|
2017-04-26 21:22:45 +00:00
|
|
|
use metadata;
|
2017-09-13 22:24:13 +00:00
|
|
|
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
2017-05-27 18:48:09 +00:00
|
|
|
use rustc::middle::lang_items::StartFnLangItem;
|
2018-04-04 23:54:30 +00:00
|
|
|
use rustc::middle::weak_lang_items;
|
2017-10-27 08:50:39 +00:00
|
|
|
use rustc::mir::mono::{Linkage, Visibility, Stats};
|
|
|
|
use rustc::middle::cstore::{EncodedMetadata};
|
2016-12-31 23:00:24 +00:00
|
|
|
use rustc::ty::{self, Ty, TyCtxt};
|
2017-09-21 17:40:50 +00:00
|
|
|
use rustc::ty::layout::{self, Align, TyLayout, LayoutOf};
|
2018-06-13 13:44:43 +00:00
|
|
|
use rustc::ty::query::Providers;
|
2017-12-19 17:01:19 +00:00
|
|
|
use rustc::dep_graph::{DepNode, DepConstructor};
|
2017-08-31 19:08:29 +00:00
|
|
|
use rustc::middle::cstore::{self, LinkMeta, LinkagePreference};
|
2018-03-05 16:41:11 +00:00
|
|
|
use rustc::middle::exported_symbols;
|
2017-07-31 12:51:47 +00:00
|
|
|
use rustc::util::common::{time, print_time_passes_entry};
|
2018-05-19 17:50:58 +00:00
|
|
|
use rustc::util::profiling::ProfileCategory;
|
2018-07-26 17:41:10 +00:00
|
|
|
use rustc::session::config::{self, DebugInfo, EntryFnType};
|
2017-05-22 18:20:12 +00:00
|
|
|
use rustc::session::Session;
|
2017-09-18 16:03:09 +00:00
|
|
|
use rustc_incremental;
|
2017-06-03 21:54:08 +00:00
|
|
|
use allocator;
|
2017-12-01 12:39:51 +00:00
|
|
|
use mir::place::PlaceRef;
|
2016-03-22 17:23:36 +00:00
|
|
|
use attributes;
|
2018-05-11 10:26:32 +00:00
|
|
|
use builder::{Builder, MemFlags};
|
2017-03-08 16:33:21 +00:00
|
|
|
use callee;
|
2017-08-05 09:27:28 +00:00
|
|
|
use common::{C_bool, C_bytes_in_context, C_i32, C_usize};
|
2017-10-25 15:05:19 +00:00
|
|
|
use rustc_mir::monomorphize::collector::{self, MonoItemCollectionMode};
|
2018-06-15 17:02:41 +00:00
|
|
|
use rustc_mir::monomorphize::item::DefPathBasedNames;
|
2018-01-05 04:14:44 +00:00
|
|
|
use common::{self, C_struct_in_context, C_array, val_ty};
|
2016-03-22 17:23:36 +00:00
|
|
|
use consts;
|
2018-06-27 14:57:25 +00:00
|
|
|
use context::CodegenCx;
|
2016-12-16 20:25:18 +00:00
|
|
|
use debuginfo;
|
2016-03-22 17:23:36 +00:00
|
|
|
use declare;
|
|
|
|
use meth;
|
|
|
|
use mir;
|
2017-06-25 09:41:24 +00:00
|
|
|
use monomorphize::Instance;
|
2017-11-23 15:02:02 +00:00
|
|
|
use monomorphize::partitioning::{self, PartitioningStrategy, CodegenUnit, CodegenUnitExt};
|
2018-05-08 13:10:16 +00:00
|
|
|
use rustc_codegen_utils::symbol_names_test;
|
2017-07-27 11:02:31 +00:00
|
|
|
use time_graph;
|
2018-06-15 17:02:41 +00:00
|
|
|
use mono_item::{MonoItem, BaseMonoItemExt, MonoItemExt};
|
2016-03-22 17:23:36 +00:00
|
|
|
use type_::Type;
|
2017-09-21 17:40:50 +00:00
|
|
|
use type_of::LayoutLlvmExt;
|
2018-02-23 15:25:03 +00:00
|
|
|
use rustc::util::nodemap::{FxHashMap, FxHashSet, DefIdSet};
|
2017-08-28 22:55:32 +00:00
|
|
|
use CrateInfo;
|
2018-02-10 22:28:17 +00:00
|
|
|
use rustc_data_structures::sync::Lrc;
|
2013-06-16 10:52:44 +00:00
|
|
|
|
2017-09-13 23:03:24 +00:00
|
|
|
use std::any::Any;
|
2017-10-17 20:08:13 +00:00
|
|
|
use std::ffi::CString;
|
2017-07-12 15:37:58 +00:00
|
|
|
use std::sync::Arc;
|
2017-07-31 12:51:47 +00:00
|
|
|
use std::time::{Instant, Duration};
|
2018-03-31 20:42:35 +00:00
|
|
|
use std::i32;
|
|
|
|
use std::cmp;
|
2017-09-13 23:03:24 +00:00
|
|
|
use std::sync::mpsc;
|
2017-03-07 23:41:26 +00:00
|
|
|
use syntax_pos::Span;
|
2017-09-14 03:26:39 +00:00
|
|
|
use syntax_pos::symbol::InternedString;
|
2015-09-14 09:58:20 +00:00
|
|
|
use syntax::attr;
|
2018-07-13 18:30:47 +00:00
|
|
|
use rustc::hir::{self, CodegenFnAttrs};
|
2012-03-04 01:49:23 +00:00
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
use value::Value;
|
|
|
|
|
2017-09-20 15:17:23 +00:00
|
|
|
use mir::operand::OperandValue;
|
2017-02-06 16:27:09 +00:00
|
|
|
|
2018-06-16 14:46:03 +00:00
|
|
|
use rustc_codegen_utils::check_for_rustc_errors_attr;
|
|
|
|
|
2018-07-02 14:52:53 +00:00
|
|
|
pub struct StatRecorder<'a, 'll: 'a, 'tcx: 'll> {
|
|
|
|
cx: &'a CodegenCx<'ll, 'tcx>,
|
2014-05-22 23:57:53 +00:00
|
|
|
name: Option<String>,
|
2015-03-26 00:06:52 +00:00
|
|
|
istart: usize,
|
2013-06-28 18:15:34 +00:00
|
|
|
}
|
|
|
|
|
2018-07-02 14:52:53 +00:00
|
|
|
impl StatRecorder<'a, 'll, 'tcx> {
|
|
|
|
pub fn new(cx: &'a CodegenCx<'ll, 'tcx>, name: String) -> Self {
|
2018-01-05 05:04:08 +00:00
|
|
|
let istart = cx.stats.borrow().n_llvm_insns;
|
2013-06-28 18:15:34 +00:00
|
|
|
StatRecorder {
|
2018-01-05 05:04:08 +00:00
|
|
|
cx,
|
2014-02-14 05:07:09 +00:00
|
|
|
name: Some(name),
|
2017-08-07 05:54:09 +00:00
|
|
|
istart,
|
2013-06-28 18:15:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-02 14:52:53 +00:00
|
|
|
impl Drop for StatRecorder<'a, 'll, 'tcx> {
|
2013-09-17 01:18:07 +00:00
|
|
|
fn drop(&mut self) {
|
2018-05-08 13:10:16 +00:00
|
|
|
if self.cx.sess().codegen_stats() {
|
2018-01-05 05:04:08 +00:00
|
|
|
let mut stats = self.cx.stats.borrow_mut();
|
2017-09-14 03:26:39 +00:00
|
|
|
let iend = stats.n_llvm_insns;
|
|
|
|
stats.fn_stats.push((self.name.take().unwrap(), iend - self.istart));
|
|
|
|
stats.n_fns += 1;
|
2013-06-28 18:15:34 +00:00
|
|
|
// Reset LLVM insn count to avoid compound costs.
|
2017-09-14 03:26:39 +00:00
|
|
|
stats.n_llvm_insns = self.istart;
|
2013-06-28 18:15:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-11 10:44:53 +00:00
|
|
|
pub fn bin_op_to_icmp_predicate(op: hir::BinOpKind,
|
2015-11-19 11:36:31 +00:00
|
|
|
signed: bool)
|
2015-01-29 12:03:34 +00:00
|
|
|
-> llvm::IntPredicate {
|
|
|
|
match op {
|
2018-07-11 10:44:53 +00:00
|
|
|
hir::BinOpKind::Eq => llvm::IntEQ,
|
|
|
|
hir::BinOpKind::Ne => llvm::IntNE,
|
|
|
|
hir::BinOpKind::Lt => if signed { llvm::IntSLT } else { llvm::IntULT },
|
|
|
|
hir::BinOpKind::Le => if signed { llvm::IntSLE } else { llvm::IntULE },
|
|
|
|
hir::BinOpKind::Gt => if signed { llvm::IntSGT } else { llvm::IntUGT },
|
|
|
|
hir::BinOpKind::Ge => if signed { llvm::IntSGE } else { llvm::IntUGE },
|
2015-01-29 12:03:34 +00:00
|
|
|
op => {
|
2016-03-28 23:46:02 +00:00
|
|
|
bug!("comparison_op_to_icmp_predicate: expected comparison operator, \
|
|
|
|
found {:?}",
|
|
|
|
op)
|
2015-01-29 12:03:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-06-15 18:19:50 +00:00
|
|
|
|
2018-07-11 10:44:53 +00:00
|
|
|
pub fn bin_op_to_fcmp_predicate(op: hir::BinOpKind) -> llvm::RealPredicate {
|
2015-01-29 12:03:34 +00:00
|
|
|
match op {
|
2018-07-11 10:44:53 +00:00
|
|
|
hir::BinOpKind::Eq => llvm::RealOEQ,
|
|
|
|
hir::BinOpKind::Ne => llvm::RealUNE,
|
|
|
|
hir::BinOpKind::Lt => llvm::RealOLT,
|
|
|
|
hir::BinOpKind::Le => llvm::RealOLE,
|
|
|
|
hir::BinOpKind::Gt => llvm::RealOGT,
|
|
|
|
hir::BinOpKind::Ge => llvm::RealOGE,
|
2015-01-29 12:03:34 +00:00
|
|
|
op => {
|
2016-03-28 23:46:02 +00:00
|
|
|
bug!("comparison_op_to_fcmp_predicate: expected comparison operator, \
|
|
|
|
found {:?}",
|
|
|
|
op);
|
2015-01-29 12:03:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-02 14:52:53 +00:00
|
|
|
pub fn compare_simd_types(
|
|
|
|
bx: &Builder<'a, 'll, 'tcx>,
|
2018-07-10 10:28:39 +00:00
|
|
|
lhs: &'ll Value,
|
|
|
|
rhs: &'ll Value,
|
2016-12-18 02:54:32 +00:00
|
|
|
t: Ty<'tcx>,
|
2018-07-02 14:52:53 +00:00
|
|
|
ret_ty: &'ll Type,
|
2018-07-11 10:44:53 +00:00
|
|
|
op: hir::BinOpKind
|
2018-07-10 10:28:39 +00:00
|
|
|
) -> &'ll Value {
|
2015-01-29 12:03:34 +00:00
|
|
|
let signed = match t.sty {
|
2015-06-11 23:21:46 +00:00
|
|
|
ty::TyFloat(_) => {
|
2016-03-28 23:46:02 +00:00
|
|
|
let cmp = bin_op_to_fcmp_predicate(op);
|
2018-01-05 05:12:32 +00:00
|
|
|
return bx.sext(bx.fcmp(cmp, lhs, rhs), ret_ty);
|
2015-01-28 09:20:55 +00:00
|
|
|
},
|
2015-06-11 23:21:46 +00:00
|
|
|
ty::TyUint(_) => false,
|
|
|
|
ty::TyInt(_) => true,
|
2016-03-28 23:46:02 +00:00
|
|
|
_ => bug!("compare_simd_types: invalid SIMD type"),
|
2015-01-28 09:20:55 +00:00
|
|
|
};
|
2015-01-29 12:03:34 +00:00
|
|
|
|
2016-03-28 23:46:02 +00:00
|
|
|
let cmp = bin_op_to_icmp_predicate(op, signed);
|
2015-01-28 09:20:55 +00:00
|
|
|
// LLVM outputs an `< size x i1 >`, so we need to perform a sign extension
|
|
|
|
// to get the correctly sized type. This will compile to a single instruction
|
|
|
|
// once the IR is converted to assembly if the SIMD instruction is supported
|
|
|
|
// by the target architecture.
|
2018-01-05 05:12:32 +00:00
|
|
|
bx.sext(bx.icmp(cmp, lhs, rhs), ret_ty)
|
2014-05-02 18:04:46 +00:00
|
|
|
}
|
|
|
|
|
2015-11-11 20:02:51 +00:00
|
|
|
/// Retrieve the information we are losing (making dynamic) in an unsizing
|
|
|
|
/// adjustment.
|
|
|
|
///
|
|
|
|
/// The `old_info` argument is a bit funny. It is intended for use
|
2017-08-10 22:16:18 +00:00
|
|
|
/// in an upcast, where the new vtable for an object will be derived
|
2015-11-11 20:02:51 +00:00
|
|
|
/// from the old one.
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn unsized_info(
|
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
source: Ty<'tcx>,
|
|
|
|
target: Ty<'tcx>,
|
|
|
|
old_info: Option<&'ll Value>,
|
|
|
|
) -> &'ll Value {
|
2018-01-05 05:04:08 +00:00
|
|
|
let (source, target) = cx.tcx.struct_lockstep_tails(source, target);
|
2015-11-11 20:02:51 +00:00
|
|
|
match (&source.sty, &target.sty) {
|
2017-08-05 13:11:24 +00:00
|
|
|
(&ty::TyArray(_, len), &ty::TySlice(_)) => {
|
2018-04-26 07:18:19 +00:00
|
|
|
C_usize(cx, len.unwrap_usize(cx.tcx))
|
2017-08-05 13:11:24 +00:00
|
|
|
}
|
2016-11-16 16:21:49 +00:00
|
|
|
(&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
|
2015-11-11 20:02:51 +00:00
|
|
|
// For now, upcasts are limited to changes in marker
|
|
|
|
// traits, and hence never actually require an actual
|
|
|
|
// change to the vtable.
|
|
|
|
old_info.expect("unsized_info: missing old info for trait upcast")
|
|
|
|
}
|
2016-11-16 16:21:49 +00:00
|
|
|
(_, &ty::TyDynamic(ref data, ..)) => {
|
2018-01-05 05:04:08 +00:00
|
|
|
let vtable_ptr = cx.layout_of(cx.tcx.mk_mut_ptr(target))
|
|
|
|
.field(cx, abi::FAT_PTR_EXTRA);
|
|
|
|
consts::ptrcast(meth::get_vtable(cx, source, data.principal()),
|
|
|
|
vtable_ptr.llvm_type(cx))
|
2015-11-11 20:02:51 +00:00
|
|
|
}
|
2016-03-28 23:46:02 +00:00
|
|
|
_ => bug!("unsized_info: invalid unsizing {:?} -> {:?}",
|
2015-11-11 20:02:51 +00:00
|
|
|
source,
|
2016-03-28 23:46:02 +00:00
|
|
|
target),
|
2015-11-11 20:02:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer.
|
2018-07-02 14:52:53 +00:00
|
|
|
pub fn unsize_thin_ptr(
|
|
|
|
bx: &Builder<'a, 'll, 'tcx>,
|
2018-07-10 10:28:39 +00:00
|
|
|
src: &'ll Value,
|
2016-12-18 02:54:32 +00:00
|
|
|
src_ty: Ty<'tcx>,
|
|
|
|
dst_ty: Ty<'tcx>
|
2018-07-10 10:28:39 +00:00
|
|
|
) -> (&'ll Value, &'ll Value) {
|
2015-11-11 20:02:51 +00:00
|
|
|
debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty);
|
|
|
|
match (&src_ty.sty, &dst_ty.sty) {
|
2018-05-02 13:21:05 +00:00
|
|
|
(&ty::TyRef(_, a, _),
|
|
|
|
&ty::TyRef(_, b, _)) |
|
|
|
|
(&ty::TyRef(_, a, _),
|
2015-11-11 20:02:51 +00:00
|
|
|
&ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) |
|
|
|
|
(&ty::TyRawPtr(ty::TypeAndMut { ty: a, .. }),
|
|
|
|
&ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => {
|
2018-01-05 05:12:32 +00:00
|
|
|
assert!(bx.cx.type_is_sized(a));
|
|
|
|
let ptr_ty = bx.cx.layout_of(b).llvm_type(bx.cx).ptr_to();
|
|
|
|
(bx.pointercast(src, ptr_ty), unsized_info(bx.cx, a, b, None))
|
2015-11-11 20:02:51 +00:00
|
|
|
}
|
2017-01-21 14:40:31 +00:00
|
|
|
(&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
|
|
|
|
let (a, b) = (src_ty.boxed_ty(), dst_ty.boxed_ty());
|
2018-01-05 05:12:32 +00:00
|
|
|
assert!(bx.cx.type_is_sized(a));
|
|
|
|
let ptr_ty = bx.cx.layout_of(b).llvm_type(bx.cx).ptr_to();
|
|
|
|
(bx.pointercast(src, ptr_ty), unsized_info(bx.cx, a, b, None))
|
2017-01-21 14:40:31 +00:00
|
|
|
}
|
2017-10-09 16:56:41 +00:00
|
|
|
(&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => {
|
|
|
|
assert_eq!(def_a, def_b);
|
|
|
|
|
2018-01-05 05:12:32 +00:00
|
|
|
let src_layout = bx.cx.layout_of(src_ty);
|
|
|
|
let dst_layout = bx.cx.layout_of(dst_ty);
|
2017-10-09 16:56:41 +00:00
|
|
|
let mut result = None;
|
|
|
|
for i in 0..src_layout.fields.count() {
|
2018-01-05 05:12:32 +00:00
|
|
|
let src_f = src_layout.field(bx.cx, i);
|
2017-10-09 16:56:41 +00:00
|
|
|
assert_eq!(src_layout.fields.offset(i).bytes(), 0);
|
|
|
|
assert_eq!(dst_layout.fields.offset(i).bytes(), 0);
|
|
|
|
if src_f.is_zst() {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
assert_eq!(src_layout.size, src_f.size);
|
|
|
|
|
2018-01-05 05:12:32 +00:00
|
|
|
let dst_f = dst_layout.field(bx.cx, i);
|
2017-10-09 16:56:41 +00:00
|
|
|
assert_ne!(src_f.ty, dst_f.ty);
|
|
|
|
assert_eq!(result, None);
|
2018-01-05 05:12:32 +00:00
|
|
|
result = Some(unsize_thin_ptr(bx, src, src_f.ty, dst_f.ty));
|
2017-10-09 16:56:41 +00:00
|
|
|
}
|
|
|
|
let (lldata, llextra) = result.unwrap();
|
|
|
|
// HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
|
Store scalar pair bools as i8 in memory
We represent `bool` as `i1` in a `ScalarPair`, unlike other aggregates,
to optimize IR for checked operators and the like. With this patch, we
still do so when the pair is an immediate value, but we use the `i8`
memory type when the value is loaded or stored as an LLVM aggregate.
So `(bool, bool)` looks like an `{ i1, i1 }` immediate, but `{ i8, i8 }`
in memory. When a pair is a direct function argument, `PassMode::Pair`,
it is still passed using the immediate `i1` type, but as a return value
it will use the `i8` memory type. Also, `bool`-like` enum tags will now
use scalar pairs when possible, where they were previously excluded due
to optimization issues.
2018-06-15 22:47:54 +00:00
|
|
|
(bx.bitcast(lldata, dst_layout.scalar_pair_element_llvm_type(bx.cx, 0, true)),
|
|
|
|
bx.bitcast(llextra, dst_layout.scalar_pair_element_llvm_type(bx.cx, 1, true)))
|
2017-10-09 16:56:41 +00:00
|
|
|
}
|
2016-03-28 23:46:02 +00:00
|
|
|
_ => bug!("unsize_thin_ptr: called on bad types"),
|
2015-11-11 20:02:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Coerce `src`, which is a reference to a value of type `src_ty`,
|
|
|
|
/// to a value of type `dst_ty` and store the result in `dst`
|
2018-07-02 14:52:53 +00:00
|
|
|
pub fn coerce_unsized_into(
|
|
|
|
bx: &Builder<'a, 'll, 'tcx>,
|
2018-07-10 10:28:39 +00:00
|
|
|
src: PlaceRef<'ll, 'tcx>,
|
|
|
|
dst: PlaceRef<'ll, 'tcx>
|
2018-07-02 14:52:53 +00:00
|
|
|
) {
|
2017-09-20 15:17:23 +00:00
|
|
|
let src_ty = src.layout.ty;
|
|
|
|
let dst_ty = dst.layout.ty;
|
2017-01-21 14:40:31 +00:00
|
|
|
let coerce_ptr = || {
|
2018-01-05 05:12:32 +00:00
|
|
|
let (base, info) = match src.load(bx).val {
|
2017-06-25 09:41:24 +00:00
|
|
|
OperandValue::Pair(base, info) => {
|
|
|
|
// fat-ptr to fat-ptr unsize preserves the vtable
|
|
|
|
// i.e. &'a fmt::Debug+Send => &'a fmt::Debug
|
|
|
|
// So we need to pointercast the base to ensure
|
|
|
|
// the types match up.
|
2018-01-05 05:12:32 +00:00
|
|
|
let thin_ptr = dst.layout.field(bx.cx, abi::FAT_PTR_ADDR);
|
|
|
|
(bx.pointercast(base, thin_ptr.llvm_type(bx.cx)), info)
|
2017-06-25 09:41:24 +00:00
|
|
|
}
|
|
|
|
OperandValue::Immediate(base) => {
|
2018-01-05 05:12:32 +00:00
|
|
|
unsize_thin_ptr(bx, base, src_ty, dst_ty)
|
2017-06-25 09:41:24 +00:00
|
|
|
}
|
|
|
|
OperandValue::Ref(..) => bug!()
|
2017-01-21 14:40:31 +00:00
|
|
|
};
|
2018-01-05 05:12:32 +00:00
|
|
|
OperandValue::Pair(base, info).store(bx, dst);
|
2017-01-21 14:40:31 +00:00
|
|
|
};
|
2015-11-11 20:02:51 +00:00
|
|
|
match (&src_ty.sty, &dst_ty.sty) {
|
|
|
|
(&ty::TyRef(..), &ty::TyRef(..)) |
|
|
|
|
(&ty::TyRef(..), &ty::TyRawPtr(..)) |
|
|
|
|
(&ty::TyRawPtr(..), &ty::TyRawPtr(..)) => {
|
2017-01-21 14:40:31 +00:00
|
|
|
coerce_ptr()
|
|
|
|
}
|
|
|
|
(&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
|
|
|
|
coerce_ptr()
|
2015-11-11 20:02:51 +00:00
|
|
|
}
|
|
|
|
|
2017-06-25 09:41:24 +00:00
|
|
|
(&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => {
|
2015-11-11 20:02:51 +00:00
|
|
|
assert_eq!(def_a, def_b);
|
|
|
|
|
2017-06-25 09:41:24 +00:00
|
|
|
for i in 0..def_a.variants[0].fields.len() {
|
2018-01-05 05:12:32 +00:00
|
|
|
let src_f = src.project_field(bx, i);
|
|
|
|
let dst_f = dst.project_field(bx, i);
|
2015-11-11 20:02:51 +00:00
|
|
|
|
2017-09-20 15:17:23 +00:00
|
|
|
if dst_f.layout.is_zst() {
|
2015-11-19 11:36:31 +00:00
|
|
|
continue;
|
|
|
|
}
|
2015-11-11 20:02:51 +00:00
|
|
|
|
2017-09-20 15:17:23 +00:00
|
|
|
if src_f.layout.ty == dst_f.layout.ty {
|
2018-01-05 05:12:32 +00:00
|
|
|
memcpy_ty(bx, dst_f.llval, src_f.llval, src_f.layout,
|
2018-05-11 10:26:32 +00:00
|
|
|
src_f.align.min(dst_f.align), MemFlags::empty());
|
2015-11-11 20:02:51 +00:00
|
|
|
} else {
|
2018-01-05 05:12:32 +00:00
|
|
|
coerce_unsized_into(bx, src_f, dst_f);
|
2015-11-11 20:02:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-03-28 23:46:02 +00:00
|
|
|
_ => bug!("coerce_unsized_into: invalid coercion {:?} -> {:?}",
|
|
|
|
src_ty,
|
|
|
|
dst_ty),
|
2015-11-11 20:02:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-11 15:59:20 +00:00
|
|
|
pub fn cast_shift_expr_rhs(
|
2018-07-10 10:28:39 +00:00
|
|
|
cx: &Builder<'_, 'll, '_>, op: hir::BinOpKind, lhs: &'ll Value, rhs: &'ll Value
|
|
|
|
) -> &'ll Value {
|
2016-12-11 15:59:20 +00:00
|
|
|
cast_shift_rhs(op, lhs, rhs, |a, b| cx.trunc(a, b), |a, b| cx.zext(a, b))
|
2012-02-22 05:01:33 +00:00
|
|
|
}
|
|
|
|
|
2018-07-02 14:52:53 +00:00
|
|
|
fn cast_shift_rhs<'ll, F, G>(op: hir::BinOpKind,
|
2018-07-10 10:28:39 +00:00
|
|
|
lhs: &'ll Value,
|
|
|
|
rhs: &'ll Value,
|
2015-03-19 18:52:08 +00:00
|
|
|
trunc: F,
|
|
|
|
zext: G)
|
2018-07-10 10:28:39 +00:00
|
|
|
-> &'ll Value
|
|
|
|
where F: FnOnce(&'ll Value, &'ll Type) -> &'ll Value,
|
|
|
|
G: FnOnce(&'ll Value, &'ll Type) -> &'ll Value
|
2014-12-09 18:44:51 +00:00
|
|
|
{
|
2012-02-22 05:01:33 +00:00
|
|
|
// Shifts may have any size int on the rhs
|
2016-03-29 06:32:58 +00:00
|
|
|
if op.is_shift() {
|
2015-01-14 14:08:22 +00:00
|
|
|
let mut rhs_llty = val_ty(rhs);
|
|
|
|
let mut lhs_llty = val_ty(lhs);
|
2018-07-04 13:36:49 +00:00
|
|
|
if rhs_llty.kind() == TypeKind::Vector {
|
2015-11-19 11:36:31 +00:00
|
|
|
rhs_llty = rhs_llty.element_type()
|
|
|
|
}
|
2018-07-04 13:36:49 +00:00
|
|
|
if lhs_llty.kind() == TypeKind::Vector {
|
2015-11-19 11:36:31 +00:00
|
|
|
lhs_llty = lhs_llty.element_type()
|
|
|
|
}
|
2015-01-14 14:08:22 +00:00
|
|
|
let rhs_sz = rhs_llty.int_width();
|
|
|
|
let lhs_sz = lhs_llty.int_width();
|
|
|
|
if lhs_sz < rhs_sz {
|
|
|
|
trunc(rhs, lhs_llty)
|
|
|
|
} else if lhs_sz > rhs_sz {
|
|
|
|
// FIXME (#1877: If shifting by negative
|
|
|
|
// values becomes not undefined then this is wrong.
|
|
|
|
zext(rhs, lhs_llty)
|
2012-02-22 05:01:33 +00:00
|
|
|
} else {
|
|
|
|
rhs
|
|
|
|
}
|
2015-01-14 14:08:22 +00:00
|
|
|
} else {
|
|
|
|
rhs
|
2012-02-22 05:01:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-11 18:48:43 +00:00
|
|
|
/// Returns whether this session's target will use SEH-based unwinding.
|
|
|
|
///
|
|
|
|
/// This is only true for MSVC targets, and even then the 64-bit MSVC target
|
|
|
|
/// currently uses SEH-ish unwinding with DWARF info tables to the side (same as
|
|
|
|
/// 64-bit MinGW) instead of "full SEH".
|
|
|
|
pub fn wants_msvc_seh(sess: &Session) -> bool {
|
2015-10-24 01:18:44 +00:00
|
|
|
sess.target.target.options.is_like_msvc
|
2015-08-11 18:48:43 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn call_assume(bx: &Builder<'_, 'll, '_>, val: &'ll Value) {
|
2018-01-05 05:12:32 +00:00
|
|
|
let assume_intrinsic = bx.cx.get_intrinsic("llvm.assume");
|
|
|
|
bx.call(assume_intrinsic, &[val], None);
|
2016-10-04 16:24:49 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn from_immediate(bx: &Builder<'_, 'll, '_>, val: &'ll Value) -> &'ll Value {
|
2018-01-05 05:12:32 +00:00
|
|
|
if val_ty(val) == Type::i1(bx.cx) {
|
|
|
|
bx.zext(val, Type::i8(bx.cx))
|
2015-03-20 23:21:38 +00:00
|
|
|
} else {
|
|
|
|
val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-17 15:26:58 +00:00
|
|
|
pub fn to_immediate(
|
|
|
|
bx: &Builder<'_, 'll, '_>,
|
|
|
|
val: &'ll Value,
|
|
|
|
layout: layout::TyLayout,
|
|
|
|
) -> &'ll Value {
|
2017-09-26 11:41:06 +00:00
|
|
|
if let layout::Abi::Scalar(ref scalar) = layout.abi {
|
Store scalar pair bools as i8 in memory
We represent `bool` as `i1` in a `ScalarPair`, unlike other aggregates,
to optimize IR for checked operators and the like. With this patch, we
still do so when the pair is an immediate value, but we use the `i8`
memory type when the value is loaded or stored as an LLVM aggregate.
So `(bool, bool)` looks like an `{ i1, i1 }` immediate, but `{ i8, i8 }`
in memory. When a pair is a direct function argument, `PassMode::Pair`,
it is still passed using the immediate `i1` type, but as a return value
it will use the `i8` memory type. Also, `bool`-like` enum tags will now
use scalar pairs when possible, where they were previously excluded due
to optimization issues.
2018-06-15 22:47:54 +00:00
|
|
|
return to_immediate_scalar(bx, val, scalar);
|
|
|
|
}
|
|
|
|
val
|
|
|
|
}
|
|
|
|
|
2018-07-17 15:26:58 +00:00
|
|
|
pub fn to_immediate_scalar(
|
|
|
|
bx: &Builder<'_, 'll, '_>,
|
|
|
|
val: &'ll Value,
|
|
|
|
scalar: &layout::Scalar,
|
|
|
|
) -> &'ll Value {
|
Store scalar pair bools as i8 in memory
We represent `bool` as `i1` in a `ScalarPair`, unlike other aggregates,
to optimize IR for checked operators and the like. With this patch, we
still do so when the pair is an immediate value, but we use the `i8`
memory type when the value is loaded or stored as an LLVM aggregate.
So `(bool, bool)` looks like an `{ i1, i1 }` immediate, but `{ i8, i8 }`
in memory. When a pair is a direct function argument, `PassMode::Pair`,
it is still passed using the immediate `i1` type, but as a return value
it will use the `i8` memory type. Also, `bool`-like` enum tags will now
use scalar pairs when possible, where they were previously excluded due
to optimization issues.
2018-06-15 22:47:54 +00:00
|
|
|
if scalar.is_bool() {
|
|
|
|
return bx.trunc(val, Type::i1(bx.cx));
|
2015-03-20 23:21:38 +00:00
|
|
|
}
|
2017-09-26 11:41:06 +00:00
|
|
|
val
|
2015-03-20 23:21:38 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn call_memcpy(
|
|
|
|
bx: &Builder<'_, 'll, '_>,
|
|
|
|
dst: &'ll Value,
|
|
|
|
src: &'ll Value,
|
|
|
|
n_bytes: &'ll Value,
|
|
|
|
align: Align,
|
|
|
|
flags: MemFlags,
|
|
|
|
) {
|
2018-05-11 10:26:32 +00:00
|
|
|
if flags.contains(MemFlags::NONTEMPORAL) {
|
|
|
|
// HACK(nox): This is inefficient but there is no nontemporal memcpy.
|
|
|
|
let val = bx.load(src, align);
|
|
|
|
let ptr = bx.pointercast(dst, val_ty(val).ptr_to());
|
|
|
|
bx.store_with_flags(val, ptr, align, flags);
|
|
|
|
return;
|
|
|
|
}
|
2018-01-05 05:12:32 +00:00
|
|
|
let cx = bx.cx;
|
2018-01-05 05:04:08 +00:00
|
|
|
let ptr_width = &cx.sess().target.target.target_pointer_width;
|
2015-08-15 06:43:39 +00:00
|
|
|
let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width);
|
2018-01-05 05:04:08 +00:00
|
|
|
let memcpy = cx.get_intrinsic(&key);
|
2018-01-05 05:12:32 +00:00
|
|
|
let src_ptr = bx.pointercast(src, Type::i8p(cx));
|
|
|
|
let dst_ptr = bx.pointercast(dst, Type::i8p(cx));
|
|
|
|
let size = bx.intcast(n_bytes, cx.isize_ty, false);
|
2018-01-05 05:04:08 +00:00
|
|
|
let align = C_i32(cx, align.abi() as i32);
|
2018-05-11 10:26:32 +00:00
|
|
|
let volatile = C_bool(cx, flags.contains(MemFlags::VOLATILE));
|
2018-01-05 05:12:32 +00:00
|
|
|
bx.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None);
|
2012-08-28 22:54:45 +00:00
|
|
|
}
|
|
|
|
|
2018-07-02 14:52:53 +00:00
|
|
|
pub fn memcpy_ty(
|
2018-07-10 10:28:39 +00:00
|
|
|
bx: &Builder<'_, 'll, 'tcx>,
|
|
|
|
dst: &'ll Value,
|
|
|
|
src: &'ll Value,
|
2017-09-21 17:40:50 +00:00
|
|
|
layout: TyLayout<'tcx>,
|
2017-12-01 22:28:43 +00:00
|
|
|
align: Align,
|
2018-05-11 10:26:32 +00:00
|
|
|
flags: MemFlags,
|
2016-12-31 23:00:24 +00:00
|
|
|
) {
|
2017-09-22 19:44:40 +00:00
|
|
|
let size = layout.size.bytes();
|
2017-03-02 03:35:25 +00:00
|
|
|
if size == 0 {
|
2015-08-22 15:07:37 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-05-11 10:26:32 +00:00
|
|
|
call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, flags);
|
2012-08-28 22:54:45 +00:00
|
|
|
}
|
|
|
|
|
2018-07-02 14:52:53 +00:00
|
|
|
pub fn call_memset(
|
2018-07-10 10:28:39 +00:00
|
|
|
bx: &Builder<'_, 'll, '_>,
|
|
|
|
ptr: &'ll Value,
|
|
|
|
fill_byte: &'ll Value,
|
|
|
|
size: &'ll Value,
|
|
|
|
align: &'ll Value,
|
2018-07-02 14:52:53 +00:00
|
|
|
volatile: bool,
|
2018-07-10 10:28:39 +00:00
|
|
|
) -> &'ll Value {
|
2018-01-05 05:12:32 +00:00
|
|
|
let ptr_width = &bx.cx.sess().target.target.target_pointer_width;
|
2016-02-04 17:40:28 +00:00
|
|
|
let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width);
|
2018-01-05 05:12:32 +00:00
|
|
|
let llintrinsicfn = bx.cx.get_intrinsic(&intrinsic_key);
|
|
|
|
let volatile = C_bool(bx.cx, volatile);
|
|
|
|
bx.call(llintrinsicfn, &[ptr, fill_byte, size, align, volatile], None)
|
2016-02-04 17:40:28 +00:00
|
|
|
}
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
pub fn codegen_instance<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, instance: Instance<'tcx>) {
|
|
|
|
let _s = if cx.sess().codegen_stats() {
|
2016-11-04 21:37:42 +00:00
|
|
|
let mut instance_name = String::new();
|
2018-01-05 05:04:08 +00:00
|
|
|
DefPathBasedNames::new(cx.tcx, true, true)
|
2017-02-08 17:31:03 +00:00
|
|
|
.push_def_path(instance.def_id(), &mut instance_name);
|
2018-01-05 05:04:08 +00:00
|
|
|
Some(StatRecorder::new(cx, instance_name))
|
2016-11-04 21:37:42 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2016-11-09 21:09:28 +00:00
|
|
|
// this is an info! to allow collecting monomorphization statistics
|
|
|
|
// and to allow finding the last function before LLVM aborts from
|
|
|
|
// release builds.
|
2018-05-08 13:10:16 +00:00
|
|
|
info!("codegen_instance({})", instance);
|
2016-11-09 21:09:28 +00:00
|
|
|
|
2018-01-05 05:04:08 +00:00
|
|
|
let fn_ty = instance.ty(cx.tcx);
|
|
|
|
let sig = common::ty_fn_sig(cx, fn_ty);
|
2018-03-03 13:23:28 +00:00
|
|
|
let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
|
2016-11-09 21:09:28 +00:00
|
|
|
|
2018-01-05 05:04:08 +00:00
|
|
|
let lldecl = match cx.instances.borrow().get(&instance) {
|
2016-11-09 21:09:28 +00:00
|
|
|
Some(&val) => val,
|
|
|
|
None => bug!("Instance `{:?}` not already declared", instance)
|
|
|
|
};
|
|
|
|
|
2018-01-05 05:04:08 +00:00
|
|
|
cx.stats.borrow_mut().n_closures += 1;
|
2013-12-22 21:50:04 +00:00
|
|
|
|
2017-03-15 15:09:59 +00:00
|
|
|
// The `uwtable` attribute according to LLVM is:
|
|
|
|
//
|
|
|
|
// This attribute indicates that the ABI being targeted requires that an
|
|
|
|
// unwind table entry be produced for this function even if we can show
|
|
|
|
// that no exceptions passes by it. This is normally the case for the
|
|
|
|
// ELF x86-64 abi, but it can be disabled for some compilation units.
|
|
|
|
//
|
|
|
|
// Typically when we're compiling with `-C panic=abort` (which implies this
|
|
|
|
// `no_landing_pads` check) we don't need `uwtable` because we can't
|
|
|
|
// generate any exceptions! On Windows, however, exceptions include other
|
|
|
|
// events such as illegal instructions, segfaults, etc. This means that on
|
|
|
|
// Windows we end up still needing the `uwtable` attribute even if the `-C
|
|
|
|
// panic=abort` flag is passed.
|
|
|
|
//
|
|
|
|
// You can also find more info on why Windows is whitelisted here in:
|
|
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1302078
|
2018-01-05 05:04:08 +00:00
|
|
|
if !cx.sess().no_landing_pads() ||
|
2018-04-19 22:17:34 +00:00
|
|
|
cx.sess().target.target.options.requires_uwtable {
|
2016-11-09 21:09:28 +00:00
|
|
|
attributes::emit_uwtable(lldecl, true);
|
rustc: Implement custom panic runtimes
This commit is an implementation of [RFC 1513] which allows applications to
alter the behavior of panics at compile time. A new compiler flag, `-C panic`,
is added and accepts the values `unwind` or `panic`, with the default being
`unwind`. This model affects how code is generated for the local crate, skipping
generation of landing pads with `-C panic=abort`.
[RFC 1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md
Panic implementations are then provided by crates tagged with
`#![panic_runtime]` and lazily required by crates with
`#![needs_panic_runtime]`. The panic strategy (`-C panic` value) of the panic
runtime must match the final product, and if the panic strategy is not `abort`
then the entire DAG must have the same panic strategy.
With the `-C panic=abort` strategy, users can expect a stable method to disable
generation of landing pads, improving optimization in niche scenarios,
decreasing compile time, and decreasing output binary size. With the `-C
panic=unwind` strategy users can expect the existing ability to isolate failure
in Rust code from the outside world.
Organizationally, this commit dismantles the `sys_common::unwind` module in
favor of some bits moving part of it to `libpanic_unwind` and the rest into the
`panicking` module in libstd. The custom panic runtime support is pretty similar
to the custom allocator support with the only major difference being how the
panic runtime is injected (takes the `-C panic` flag into account).
2016-04-08 23:18:40 +00:00
|
|
|
}
|
2010-11-27 01:47:27 +00:00
|
|
|
|
2018-01-05 05:04:08 +00:00
|
|
|
let mir = cx.tcx.instance_mir(instance.def);
|
2018-05-08 13:10:16 +00:00
|
|
|
mir::codegen_mir(cx, lldecl, &mir, instance, sig);
|
2011-06-30 02:50:50 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) {
|
2018-07-13 18:30:47 +00:00
|
|
|
let sect = match attrs.link_section {
|
|
|
|
Some(name) => name,
|
|
|
|
None => return,
|
|
|
|
};
|
|
|
|
unsafe {
|
|
|
|
let buf = CString::new(sect.as_str().as_bytes()).unwrap();
|
|
|
|
llvm::LLVMSetSection(llval, buf.as_ptr());
|
2015-08-03 22:38:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-15 19:45:21 +00:00
|
|
|
/// Create the `main` function which will initialize the rust runtime and call
|
2017-02-07 21:46:21 +00:00
|
|
|
/// users main function.
|
2018-01-05 05:04:08 +00:00
|
|
|
fn maybe_create_entry_wrapper(cx: &CodegenCx) {
|
|
|
|
let (main_def_id, span) = match *cx.sess().entry_fn.borrow() {
|
2018-04-01 06:17:53 +00:00
|
|
|
Some((id, span, _)) => {
|
2018-01-05 05:04:08 +00:00
|
|
|
(cx.tcx.hir.local_def_id(id), span)
|
2016-05-26 16:18:39 +00:00
|
|
|
}
|
|
|
|
None => return,
|
|
|
|
};
|
|
|
|
|
2018-01-05 05:04:08 +00:00
|
|
|
let instance = Instance::mono(cx.tcx, main_def_id);
|
2016-05-26 16:18:39 +00:00
|
|
|
|
2018-01-05 05:04:08 +00:00
|
|
|
if !cx.codegen_unit.contains_item(&MonoItem::Fn(instance)) {
|
2016-05-26 16:18:39 +00:00
|
|
|
// We want to create the wrapper in the same codegen unit as Rust's main
|
|
|
|
// function.
|
|
|
|
return;
|
2013-01-11 09:08:01 +00:00
|
|
|
}
|
|
|
|
|
2018-01-05 05:04:08 +00:00
|
|
|
let main_llfn = callee::get_fn(cx, instance);
|
2016-05-26 16:18:39 +00:00
|
|
|
|
2018-04-01 06:17:53 +00:00
|
|
|
let et = cx.sess().entry_fn.get().map(|e| e.2);
|
2013-08-04 02:59:46 +00:00
|
|
|
match et {
|
2018-07-26 17:29:45 +00:00
|
|
|
Some(EntryFnType::Main) => create_entry_fn(cx, span, main_llfn, main_def_id, true),
|
|
|
|
Some(EntryFnType::Start) => create_entry_fn(cx, span, main_llfn, main_def_id, false),
|
2018-04-01 06:17:53 +00:00
|
|
|
None => {} // Do nothing.
|
2013-04-09 08:16:06 +00:00
|
|
|
}
|
2011-08-13 01:43:44 +00:00
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
fn create_entry_fn(
|
|
|
|
cx: &CodegenCx<'ll, '_>,
|
|
|
|
sp: Span,
|
|
|
|
rust_main: &'ll Value,
|
|
|
|
rust_main_def_id: DefId,
|
|
|
|
use_start_lang_item: bool,
|
|
|
|
) {
|
2018-07-02 14:52:53 +00:00
|
|
|
let llfty = Type::func(&[Type::c_int(cx), Type::i8p(cx).ptr_to()], Type::c_int(cx));
|
2017-12-03 21:16:24 +00:00
|
|
|
|
2018-01-05 05:04:08 +00:00
|
|
|
let main_ret_ty = cx.tcx.fn_sig(rust_main_def_id).output();
|
2017-12-03 21:16:24 +00:00
|
|
|
// Given that `main()` has no arguments,
|
|
|
|
// then its return type cannot have
|
|
|
|
// late-bound regions, since late-bound
|
|
|
|
// regions must appear in the argument
|
|
|
|
// listing.
|
2018-04-05 13:50:48 +00:00
|
|
|
let main_ret_ty = cx.tcx.erase_regions(
|
|
|
|
&main_ret_ty.no_late_bound_regions().unwrap(),
|
|
|
|
);
|
2012-11-30 00:21:49 +00:00
|
|
|
|
2018-01-05 05:04:08 +00:00
|
|
|
if declare::get_defined_value(cx, "main").is_some() {
|
2015-03-03 23:08:06 +00:00
|
|
|
// FIXME: We should be smart and show a better diagnostic here.
|
2018-01-05 05:04:08 +00:00
|
|
|
cx.sess().struct_span_err(sp, "entry symbol `main` defined multiple times")
|
2015-12-20 21:00:43 +00:00
|
|
|
.help("did you use #[no_mangle] on `fn main`? Use #[start] instead")
|
|
|
|
.emit();
|
2018-01-05 05:04:08 +00:00
|
|
|
cx.sess().abort_if_errors();
|
2016-03-28 23:46:02 +00:00
|
|
|
bug!();
|
2016-02-23 19:46:08 +00:00
|
|
|
}
|
2018-01-05 05:04:08 +00:00
|
|
|
let llfn = declare::declare_cfn(cx, "main", llfty);
|
2014-08-18 18:15:05 +00:00
|
|
|
|
2016-11-03 09:53:13 +00:00
|
|
|
// `main` should respect same config for frame pointer elimination as rest of code
|
2018-01-05 05:04:08 +00:00
|
|
|
attributes::set_frame_pointer_elimination(cx, llfn);
|
2016-11-03 09:53:13 +00:00
|
|
|
|
2018-01-05 05:12:32 +00:00
|
|
|
let bx = Builder::new_block(cx, llfn, "top");
|
2014-12-03 22:48:18 +00:00
|
|
|
|
2018-01-05 05:12:32 +00:00
|
|
|
debuginfo::gdb::insert_reference_to_gdb_debug_scripts_section_global(&bx);
|
2013-04-18 22:53:29 +00:00
|
|
|
|
2017-09-21 22:36:10 +00:00
|
|
|
// Params from native main() used as args for rust start function
|
|
|
|
let param_argc = get_param(llfn, 0);
|
|
|
|
let param_argv = get_param(llfn, 1);
|
2018-01-05 05:12:32 +00:00
|
|
|
let arg_argc = bx.intcast(param_argc, cx.isize_ty, true);
|
2017-09-21 22:36:10 +00:00
|
|
|
let arg_argv = param_argv;
|
|
|
|
|
2016-12-17 01:48:25 +00:00
|
|
|
let (start_fn, args) = if use_start_lang_item {
|
2018-01-05 05:04:08 +00:00
|
|
|
let start_def_id = cx.tcx.require_lang_item(StartFnLangItem);
|
2018-04-05 13:50:48 +00:00
|
|
|
let start_fn = callee::resolve_and_get_fn(
|
|
|
|
cx,
|
|
|
|
start_def_id,
|
2018-05-16 07:38:55 +00:00
|
|
|
cx.tcx.intern_substs(&[main_ret_ty.into()]),
|
2018-04-05 13:50:48 +00:00
|
|
|
);
|
2018-01-05 05:12:32 +00:00
|
|
|
(start_fn, vec![bx.pointercast(rust_main, Type::i8p(cx).ptr_to()),
|
2017-09-21 22:36:10 +00:00
|
|
|
arg_argc, arg_argv])
|
2016-12-17 01:48:25 +00:00
|
|
|
} else {
|
|
|
|
debug!("using user-defined start fn");
|
2017-09-21 22:36:10 +00:00
|
|
|
(rust_main, vec![arg_argc, arg_argv])
|
2016-12-17 01:48:25 +00:00
|
|
|
};
|
2013-07-07 20:30:48 +00:00
|
|
|
|
2018-01-05 05:12:32 +00:00
|
|
|
let result = bx.call(start_fn, &args, None);
|
|
|
|
bx.ret(bx.intcast(result, Type::c_int(cx), true));
|
2011-10-20 11:48:10 +00:00
|
|
|
}
|
2011-02-28 22:33:46 +00:00
|
|
|
}
|
|
|
|
|
2017-04-13 22:21:51 +00:00
|
|
|
fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
|
2018-06-27 14:57:25 +00:00
|
|
|
llvm_module: &ModuleLlvm,
|
2018-02-23 15:25:03 +00:00
|
|
|
link_meta: &LinkMeta)
|
2018-06-27 14:57:25 +00:00
|
|
|
-> EncodedMetadata {
|
2017-06-08 21:10:36 +00:00
|
|
|
use std::io::Write;
|
|
|
|
use flate2::Compression;
|
2017-07-10 15:54:50 +00:00
|
|
|
use flate2::write::DeflateEncoder;
|
Store metadata separately in rlib files
Right now whenever an rlib file is linked against, all of the metadata from the
rlib is pulled in to the final staticlib or binary. The reason for this is that
the metadata is currently stored in a section of the object file. Note that this
is intentional for dynamic libraries in order to distribute metadata bundled
with static libraries.
This commit alters the situation for rlib libraries to instead store the
metadata in a separate file in the archive. In doing so, when the archive is
passed to the linker, none of the metadata will get pulled into the result
executable. Furthermore, the metadata file is skipped when assembling rlibs into
an archive.
The snag in this implementation comes with multiple output formats. When
generating a dylib, the metadata needs to be in the object file, but when
generating an rlib this needs to be separate. In order to accomplish this, the
metadata variable is inserted into an entirely separate LLVM Module which is
then codegen'd into a different location (foo.metadata.o). This is then linked
into dynamic libraries and silently ignored for rlib files.
While changing how metadata is inserted into archives, I have also stopped
compressing metadata when inserted into rlib files. We have wanted to stop
compressing metadata, but the sections it creates in object file sections are
apparently too large. Thankfully if it's just an arbitrary file it doesn't
matter how large it is.
I have seen massive reductions in executable sizes, as well as staticlib output
sizes (to confirm that this is all working).
2013-12-04 01:41:01 +00:00
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
|
2017-04-13 15:48:19 +00:00
|
|
|
|
2016-10-19 01:06:46 +00:00
|
|
|
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
|
|
|
enum MetadataKind {
|
|
|
|
None,
|
|
|
|
Uncompressed,
|
|
|
|
Compressed
|
|
|
|
}
|
|
|
|
|
2017-04-13 22:21:51 +00:00
|
|
|
let kind = tcx.sess.crate_types.borrow().iter().map(|ty| {
|
2016-10-19 01:06:46 +00:00
|
|
|
match *ty {
|
2018-07-26 17:13:11 +00:00
|
|
|
config::CrateType::Executable |
|
|
|
|
config::CrateType::Staticlib |
|
|
|
|
config::CrateType::Cdylib => MetadataKind::None,
|
2016-10-19 01:06:46 +00:00
|
|
|
|
2018-07-26 17:13:11 +00:00
|
|
|
config::CrateType::Rlib => MetadataKind::Uncompressed,
|
2016-10-19 01:06:46 +00:00
|
|
|
|
2018-07-26 17:13:11 +00:00
|
|
|
config::CrateType::Dylib |
|
|
|
|
config::CrateType::ProcMacro => MetadataKind::Compressed,
|
2016-10-19 01:06:46 +00:00
|
|
|
}
|
2018-05-24 15:05:16 +00:00
|
|
|
}).max().unwrap_or(MetadataKind::None);
|
2016-10-19 01:06:46 +00:00
|
|
|
|
|
|
|
if kind == MetadataKind::None {
|
2018-06-27 14:57:25 +00:00
|
|
|
return EncodedMetadata::new();
|
2013-12-22 22:40:03 +00:00
|
|
|
}
|
2013-06-13 07:19:50 +00:00
|
|
|
|
2018-02-23 15:25:03 +00:00
|
|
|
let metadata = tcx.encode_metadata(link_meta);
|
2016-10-19 01:06:46 +00:00
|
|
|
if kind == MetadataKind::Uncompressed {
|
2018-06-27 14:57:25 +00:00
|
|
|
return metadata;
|
2016-10-19 01:06:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
assert!(kind == MetadataKind::Compressed);
|
2017-09-07 20:21:46 +00:00
|
|
|
let mut compressed = tcx.metadata_encoding_version();
|
2017-12-29 10:24:38 +00:00
|
|
|
DeflateEncoder::new(&mut compressed, Compression::fast())
|
2017-06-08 21:10:36 +00:00
|
|
|
.write_all(&metadata.raw_data).unwrap();
|
2015-11-20 23:08:09 +00:00
|
|
|
|
2017-04-13 15:48:19 +00:00
|
|
|
let llmeta = C_bytes_in_context(metadata_llcx, &compressed);
|
|
|
|
let llconst = C_struct_in_context(metadata_llcx, &[llmeta], false);
|
2018-03-05 16:41:11 +00:00
|
|
|
let name = exported_symbols::metadata_symbol_name(tcx);
|
2015-02-18 06:47:40 +00:00
|
|
|
let buf = CString::new(name).unwrap();
|
2014-11-25 21:28:35 +00:00
|
|
|
let llglobal = unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
llvm::LLVMAddGlobal(metadata_llmod, val_ty(llconst), buf.as_ptr())
|
2014-11-25 21:28:35 +00:00
|
|
|
};
|
2013-01-11 05:23:07 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMSetInitializer(llglobal, llconst);
|
2017-04-26 21:22:45 +00:00
|
|
|
let section_name = metadata::metadata_section_name(&tcx.sess.target.target);
|
2016-08-14 08:16:28 +00:00
|
|
|
let name = CString::new(section_name).unwrap();
|
|
|
|
llvm::LLVMSetSection(llglobal, name.as_ptr());
|
|
|
|
|
|
|
|
// Also generate a .section directive to force no
|
|
|
|
// flags, at least for ELF outputs, so that the
|
|
|
|
// metadata doesn't get loaded into memory.
|
|
|
|
let directive = format!(".section {}", section_name);
|
|
|
|
let directive = CString::new(directive).unwrap();
|
2017-04-13 15:48:19 +00:00
|
|
|
llvm::LLVMSetModuleInlineAsm(metadata_llmod, directive.as_ptr())
|
2013-01-11 05:23:07 +00:00
|
|
|
}
|
2018-06-27 14:57:25 +00:00
|
|
|
return metadata;
|
2011-06-27 23:09:28 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub struct ValueIter<'ll> {
|
|
|
|
cur: Option<&'ll Value>,
|
|
|
|
step: unsafe extern "C" fn(&'ll Value) -> Option<&'ll Value>,
|
2015-08-21 07:41:07 +00:00
|
|
|
}
|
2014-08-01 17:29:44 +00:00
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
impl Iterator for ValueIter<'ll> {
|
|
|
|
type Item = &'ll Value;
|
2014-08-01 17:29:44 +00:00
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
fn next(&mut self) -> Option<&'ll Value> {
|
2015-08-21 07:41:07 +00:00
|
|
|
let old = self.cur;
|
2018-07-10 10:28:39 +00:00
|
|
|
if let Some(old) = old {
|
2015-10-18 00:15:26 +00:00
|
|
|
self.cur = unsafe { (self.step)(old) };
|
2015-08-21 07:41:07 +00:00
|
|
|
}
|
2018-07-10 10:28:39 +00:00
|
|
|
old
|
2014-08-01 17:29:44 +00:00
|
|
|
}
|
2015-08-21 07:41:07 +00:00
|
|
|
}
|
2014-08-01 17:29:44 +00:00
|
|
|
|
2018-07-10 10:28:39 +00:00
|
|
|
pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> {
|
2015-08-21 07:41:07 +00:00
|
|
|
unsafe {
|
|
|
|
ValueIter {
|
|
|
|
cur: llvm::LLVMGetFirstGlobal(llmod),
|
|
|
|
step: llvm::LLVMGetNextGlobal,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-01-02 04:54:03 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
2018-07-11 10:49:11 +00:00
|
|
|
rx: mpsc::Receiver<Box<dyn Any + Send>>)
|
2018-05-08 13:10:16 +00:00
|
|
|
-> OngoingCodegen {
|
2017-08-13 16:53:50 +00:00
|
|
|
|
2018-06-16 14:46:03 +00:00
|
|
|
check_for_rustc_errors_attr(tcx);
|
2017-07-31 16:51:39 +00:00
|
|
|
|
2017-11-25 19:13:58 +00:00
|
|
|
if let Some(true) = tcx.sess.opts.debugging_opts.thinlto {
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
if unsafe { !llvm::LLVMRustThinLTOAvailable() } {
|
|
|
|
tcx.sess.fatal("this compiler's LLVM does not support ThinLTO");
|
|
|
|
}
|
|
|
|
}
|
2017-09-18 16:03:09 +00:00
|
|
|
|
2018-03-15 15:56:45 +00:00
|
|
|
if (tcx.sess.opts.debugging_opts.pgo_gen.is_some() ||
|
|
|
|
!tcx.sess.opts.debugging_opts.pgo_use.is_empty()) &&
|
|
|
|
unsafe { !llvm::LLVMRustPGOAvailable() }
|
|
|
|
{
|
|
|
|
tcx.sess.fatal("this compiler's LLVM does not support PGO");
|
|
|
|
}
|
|
|
|
|
2017-12-19 17:01:19 +00:00
|
|
|
let crate_hash = tcx.crate_hash(LOCAL_CRATE);
|
2017-09-18 16:03:09 +00:00
|
|
|
let link_meta = link::build_link_meta(crate_hash);
|
2017-07-26 13:02:53 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
// Codegen the metadata.
|
2018-05-19 17:50:58 +00:00
|
|
|
tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen));
|
2018-07-16 06:58:29 +00:00
|
|
|
let llmod_id = "metadata";
|
2018-06-27 14:57:25 +00:00
|
|
|
let metadata_llvm_module = ModuleLlvm::new(tcx.sess, llmod_id);
|
|
|
|
let metadata = time(tcx.sess, "write metadata", || {
|
|
|
|
write_metadata(tcx, &metadata_llvm_module, &link_meta)
|
|
|
|
});
|
2018-05-19 17:50:58 +00:00
|
|
|
tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen));
|
2016-05-25 05:46:36 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
let metadata_module = ModuleCodegen {
|
2018-07-16 06:58:29 +00:00
|
|
|
name: link::METADATA_MODULE_NAME.to_string(),
|
|
|
|
llmod_id: llmod_id.to_string(),
|
2018-06-27 14:57:25 +00:00
|
|
|
source: ModuleSource::Codegened(metadata_llvm_module),
|
2017-07-25 15:26:24 +00:00
|
|
|
kind: ModuleKind::Metadata,
|
2016-05-25 05:46:36 +00:00
|
|
|
};
|
2017-06-03 21:54:08 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
let time_graph = if tcx.sess.opts.debugging_opts.codegen_time_graph {
|
2017-07-27 11:02:31 +00:00
|
|
|
Some(time_graph::TimeGraph::new())
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2016-05-25 05:46:36 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
// Skip crate items and just output metadata in -Z no-codegen mode.
|
|
|
|
if tcx.sess.opts.debugging_opts.no_codegen ||
|
|
|
|
!tcx.sess.opts.output_types.should_codegen() {
|
|
|
|
let ongoing_codegen = write::start_async_codegen(
|
2017-09-13 20:22:20 +00:00
|
|
|
tcx,
|
2017-07-27 11:02:31 +00:00
|
|
|
time_graph.clone(),
|
2017-07-26 10:35:23 +00:00
|
|
|
link_meta,
|
2017-09-13 23:03:24 +00:00
|
|
|
metadata,
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
rx,
|
|
|
|
1);
|
2017-07-26 10:35:23 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module);
|
|
|
|
ongoing_codegen.codegen_finished(tcx);
|
2017-07-26 10:35:23 +00:00
|
|
|
|
2017-11-29 15:28:25 +00:00
|
|
|
assert_and_save_dep_graph(tcx);
|
2017-07-26 13:02:53 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
ongoing_codegen.check_for_errors(tcx.sess);
|
2017-07-27 14:59:30 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
return ongoing_codegen;
|
2017-01-19 16:32:55 +00:00
|
|
|
}
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
// Run the monomorphization collector and partition the collected items into
|
2016-05-26 16:18:39 +00:00
|
|
|
// codegen units.
|
2017-09-13 22:24:13 +00:00
|
|
|
let codegen_units =
|
2018-05-08 13:10:16 +00:00
|
|
|
tcx.collect_and_partition_mono_items(LOCAL_CRATE).1;
|
2017-09-13 22:24:13 +00:00
|
|
|
let codegen_units = (*codegen_units).clone();
|
2017-07-12 15:37:58 +00:00
|
|
|
|
2017-09-26 17:43:17 +00:00
|
|
|
// Force all codegen_unit queries so they are already either red or green
|
|
|
|
// when compile_codegen_unit accesses them. We are not able to re-execute
|
|
|
|
// the codegen_unit query from just the DepNode, so an unknown color would
|
|
|
|
// lead to having to re-execute compile_codegen_unit, possibly
|
|
|
|
// unnecessarily.
|
|
|
|
if tcx.dep_graph.is_fully_enabled() {
|
|
|
|
for cgu in &codegen_units {
|
|
|
|
tcx.codegen_unit(cgu.name().clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
let ongoing_codegen = write::start_async_codegen(
|
2017-09-13 20:22:20 +00:00
|
|
|
tcx,
|
2017-07-27 11:02:31 +00:00
|
|
|
time_graph.clone(),
|
2017-07-26 13:02:53 +00:00
|
|
|
link_meta,
|
2017-09-13 23:03:24 +00:00
|
|
|
metadata,
|
rustc: Implement ThinLTO
This commit is an implementation of LLVM's ThinLTO for consumption in rustc
itself. Currently today LTO works by merging all relevant LLVM modules into one
and then running optimization passes. "Thin" LTO operates differently by having
more sharded work and allowing parallelism opportunities between optimizing
codegen units. Further down the road Thin LTO also allows *incremental* LTO
which should enable even faster release builds without compromising on the
performance we have today.
This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then
also implements two forms of ThinLTO:
* In one mode we'll *only* perform ThinLTO over the codegen units produced in a
single compilation. That is, we won't load upstream rlibs, but we'll instead
just perform ThinLTO amongst all codegen units produced by the compiler for
the local crate. This is intended to emulate a desired end point where we have
codegen units turned on by default for all crates and ThinLTO allows us to do
this without performance loss.
* In anther mode, like full LTO today, we'll optimize all upstream dependencies
in "thin" mode. Unlike today, however, this LTO step is fully parallelized so
should finish much more quickly.
There's a good bit of comments about what the implementation is doing and where
it came from, but the tl;dr; is that currently most of the support here is
copied from upstream LLVM. This code duplication is done for a number of
reasons:
* Controlling parallelism means we can use the existing jobserver support to
avoid overloading machines.
* We will likely want a slightly different form of incremental caching which
integrates with our own incremental strategy, but this is yet to be
determined.
* This buys us some flexibility about when/where we run ThinLTO, as well as
having it tailored to fit our needs for the time being.
* Finally this allows us to reuse some artifacts such as our `TargetMachine`
creation, where all our options we used today aren't necessarily supported by
upstream LLVM yet.
My hope is that we can get some experience with this copy/paste in tree and then
eventually upstream some work to LLVM itself to avoid the duplication while
still ensuring our needs are met. Otherwise I fear that maintaining these
bindings may be quite costly over the years with LLVM updates!
2017-07-23 15:14:38 +00:00
|
|
|
rx,
|
|
|
|
codegen_units.len());
|
2017-07-26 13:02:53 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
// Codegen an allocator shim, if any
|
2018-04-01 06:27:09 +00:00
|
|
|
let allocator_module = if let Some(kind) = *tcx.sess.allocator_kind.get() {
|
2018-07-16 06:58:29 +00:00
|
|
|
unsafe {
|
|
|
|
let llmod_id = "allocator";
|
2018-06-27 14:57:25 +00:00
|
|
|
let modules = ModuleLlvm::new(tcx.sess, llmod_id);
|
2018-07-16 06:58:29 +00:00
|
|
|
time(tcx.sess, "write allocator module", || {
|
2018-05-08 13:10:16 +00:00
|
|
|
allocator::codegen(tcx, &modules, kind)
|
2018-07-16 06:58:29 +00:00
|
|
|
});
|
2017-07-27 14:59:30 +00:00
|
|
|
|
2018-07-16 06:58:29 +00:00
|
|
|
Some(ModuleCodegen {
|
|
|
|
name: link::ALLOCATOR_MODULE_NAME.to_string(),
|
|
|
|
llmod_id: llmod_id.to_string(),
|
|
|
|
source: ModuleSource::Codegened(modules),
|
|
|
|
kind: ModuleKind::Allocator,
|
|
|
|
})
|
|
|
|
}
|
2017-07-27 14:59:30 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Some(allocator_module) = allocator_module {
|
2018-05-08 13:10:16 +00:00
|
|
|
ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, allocator_module);
|
2017-07-27 14:59:30 +00:00
|
|
|
}
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module);
|
2017-07-26 14:02:32 +00:00
|
|
|
|
2017-07-28 12:28:08 +00:00
|
|
|
// We sort the codegen units by size. This way we can schedule work for LLVM
|
2018-01-15 18:52:42 +00:00
|
|
|
// a bit more efficiently.
|
2017-07-28 12:28:08 +00:00
|
|
|
let codegen_units = {
|
|
|
|
let mut codegen_units = codegen_units;
|
2018-03-31 20:42:35 +00:00
|
|
|
codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate()));
|
2017-07-28 12:28:08 +00:00
|
|
|
codegen_units
|
|
|
|
};
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
let mut total_codegen_time = Duration::new(0, 0);
|
2017-09-14 03:26:39 +00:00
|
|
|
let mut all_stats = Stats::default();
|
2017-07-31 12:51:47 +00:00
|
|
|
|
2017-09-14 03:26:39 +00:00
|
|
|
for cgu in codegen_units.into_iter() {
|
2018-05-08 13:10:16 +00:00
|
|
|
ongoing_codegen.wait_for_signal_to_codegen_item();
|
|
|
|
ongoing_codegen.check_for_errors(tcx.sess);
|
2017-07-27 11:02:31 +00:00
|
|
|
|
2017-09-28 09:58:45 +00:00
|
|
|
// First, if incremental compilation is enabled, we try to re-use the
|
|
|
|
// codegen unit from the cache.
|
|
|
|
if tcx.dep_graph.is_fully_enabled() {
|
|
|
|
let cgu_id = cgu.work_product_id();
|
|
|
|
|
|
|
|
// Check whether there is a previous work-product we can
|
|
|
|
// re-use. Not only must the file exist, and the inputs not
|
|
|
|
// be dirty, but the hash of the symbols we will generate must
|
|
|
|
// be the same.
|
|
|
|
if let Some(buf) = tcx.dep_graph.previous_work_product(&cgu_id) {
|
|
|
|
let dep_node = &DepNode::new(tcx,
|
|
|
|
DepConstructor::CompileCodegenUnit(cgu.name().clone()));
|
|
|
|
|
|
|
|
// We try to mark the DepNode::CompileCodegenUnit green. If we
|
|
|
|
// succeed it means that none of the dependencies has changed
|
|
|
|
// and we can safely re-use.
|
|
|
|
if let Some(dep_node_index) = tcx.dep_graph.try_mark_green(tcx, dep_node) {
|
2018-07-16 06:58:29 +00:00
|
|
|
// Append ".rs" to LLVM module identifier.
|
|
|
|
//
|
|
|
|
// LLVM code generator emits a ".file filename" directive
|
|
|
|
// for ELF backends. Value of the "filename" is set as the
|
|
|
|
// LLVM module identifier. Due to a LLVM MC bug[1], LLVM
|
|
|
|
// crashes if the module identifier is same as other symbols
|
|
|
|
// such as a function name in the module.
|
|
|
|
// 1. http://llvm.org/bugs/show_bug.cgi?id=11479
|
|
|
|
let llmod_id = format!("{}.rs", cgu.name());
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
let module = ModuleCodegen {
|
2017-09-28 09:58:45 +00:00
|
|
|
name: cgu.name().to_string(),
|
|
|
|
source: ModuleSource::Preexisting(buf),
|
|
|
|
kind: ModuleKind::Regular,
|
2018-07-16 06:58:29 +00:00
|
|
|
llmod_id,
|
2017-09-28 09:58:45 +00:00
|
|
|
};
|
|
|
|
tcx.dep_graph.mark_loaded_from_cache(dep_node_index, true);
|
2018-05-08 13:10:16 +00:00
|
|
|
write::submit_codegened_module_to_llvm(tcx, module, 0);
|
2017-09-28 09:58:45 +00:00
|
|
|
// Continue to next cgu, this one is done.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// This can happen if files were deleted from the cache
|
|
|
|
// directory for some reason. We just re-compile then.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-23 15:14:38 +00:00
|
|
|
let _timing_guard = time_graph.as_ref().map(|time_graph| {
|
2018-05-08 13:10:16 +00:00
|
|
|
time_graph.start(write::CODEGEN_WORKER_TIMELINE,
|
|
|
|
write::CODEGEN_WORK_PACKAGE_KIND,
|
2017-07-23 15:14:38 +00:00
|
|
|
&format!("codegen {}", cgu.name()))
|
|
|
|
});
|
2017-07-28 12:28:08 +00:00
|
|
|
let start_time = Instant::now();
|
2017-09-14 03:26:39 +00:00
|
|
|
all_stats.extend(tcx.compile_codegen_unit(*cgu.name()));
|
2018-05-08 13:10:16 +00:00
|
|
|
total_codegen_time += start_time.elapsed();
|
|
|
|
ongoing_codegen.check_for_errors(tcx.sess);
|
2017-07-26 14:02:32 +00:00
|
|
|
}
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
ongoing_codegen.codegen_finished(tcx);
|
2017-09-14 03:26:39 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
// Since the main thread is sometimes blocked during codegen, we keep track
|
2017-07-31 12:51:47 +00:00
|
|
|
// -Ztime-passes output manually.
|
|
|
|
print_time_passes_entry(tcx.sess.time_passes(),
|
2018-05-08 13:10:16 +00:00
|
|
|
"codegen to LLVM IR",
|
|
|
|
total_codegen_time);
|
2017-07-31 12:51:47 +00:00
|
|
|
|
2017-09-14 03:26:39 +00:00
|
|
|
if tcx.sess.opts.incremental.is_some() {
|
2017-10-30 17:42:21 +00:00
|
|
|
::rustc_incremental::assert_module_sources::assert_module_sources(tcx);
|
2016-05-26 16:18:39 +00:00
|
|
|
}
|
|
|
|
|
2017-04-14 19:30:06 +00:00
|
|
|
symbol_names_test::report_symbol_names(tcx);
|
2016-05-26 16:18:39 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
if tcx.sess.codegen_stats() {
|
|
|
|
println!("--- codegen stats ---");
|
2017-09-14 03:26:39 +00:00
|
|
|
println!("n_glues_created: {}", all_stats.n_glues_created);
|
|
|
|
println!("n_null_glues: {}", all_stats.n_null_glues);
|
|
|
|
println!("n_real_glues: {}", all_stats.n_real_glues);
|
2014-07-16 18:27:57 +00:00
|
|
|
|
2017-09-14 03:26:39 +00:00
|
|
|
println!("n_fns: {}", all_stats.n_fns);
|
|
|
|
println!("n_inlines: {}", all_stats.n_inlines);
|
|
|
|
println!("n_closures: {}", all_stats.n_closures);
|
2014-01-09 10:06:55 +00:00
|
|
|
println!("fn stats:");
|
2017-09-14 03:26:39 +00:00
|
|
|
all_stats.fn_stats.sort_by_key(|&(_, insns)| insns);
|
|
|
|
for &(ref name, insns) in all_stats.fn_stats.iter() {
|
|
|
|
println!("{} insns, {}", insns, *name);
|
2013-06-28 18:15:34 +00:00
|
|
|
}
|
2013-06-13 02:49:01 +00:00
|
|
|
}
|
2016-05-26 16:18:39 +00:00
|
|
|
|
2018-01-05 04:14:44 +00:00
|
|
|
if tcx.sess.count_llvm_insns() {
|
2017-09-14 03:26:39 +00:00
|
|
|
for (k, v) in all_stats.llvm_insns.iter() {
|
2014-11-17 19:29:38 +00:00
|
|
|
println!("{:7} {}", *v, *k);
|
2013-06-17 04:23:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
ongoing_codegen.check_for_errors(tcx.sess);
|
2017-07-26 12:18:11 +00:00
|
|
|
|
2017-11-29 15:28:25 +00:00
|
|
|
assert_and_save_dep_graph(tcx);
|
2018-05-08 13:10:16 +00:00
|
|
|
ongoing_codegen
|
2013-06-14 04:25:12 +00:00
|
|
|
}
|
2015-11-18 10:38:50 +00:00
|
|
|
|
2017-11-29 15:28:25 +00:00
|
|
|
fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
2017-12-03 13:21:23 +00:00
|
|
|
time(tcx.sess,
|
2017-07-26 13:02:53 +00:00
|
|
|
"assert dep graph",
|
|
|
|
|| rustc_incremental::assert_dep_graph(tcx));
|
|
|
|
|
2017-12-03 13:21:23 +00:00
|
|
|
time(tcx.sess,
|
2017-07-26 13:02:53 +00:00
|
|
|
"serialize dep graph",
|
2017-11-29 15:28:25 +00:00
|
|
|
|| rustc_incremental::save_dep_graph(tcx));
|
2017-07-26 13:02:53 +00:00
|
|
|
}
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
fn collect_and_partition_mono_items<'a, 'tcx>(
|
2017-09-12 18:04:46 +00:00
|
|
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
|
|
cnum: CrateNum,
|
2017-09-13 22:24:13 +00:00
|
|
|
) -> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>)
|
2017-09-12 18:04:46 +00:00
|
|
|
{
|
|
|
|
assert_eq!(cnum, LOCAL_CRATE);
|
2015-11-02 13:46:39 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
let collection_mode = match tcx.sess.opts.debugging_opts.print_mono_items {
|
2015-11-02 13:46:39 +00:00
|
|
|
Some(ref s) => {
|
|
|
|
let mode_string = s.to_lowercase();
|
|
|
|
let mode_string = mode_string.trim();
|
|
|
|
if mode_string == "eager" {
|
2017-10-25 15:05:19 +00:00
|
|
|
MonoItemCollectionMode::Eager
|
2015-11-02 13:46:39 +00:00
|
|
|
} else {
|
|
|
|
if mode_string != "lazy" {
|
|
|
|
let message = format!("Unknown codegen-item collection mode '{}'. \
|
|
|
|
Falling back to 'lazy' mode.",
|
|
|
|
mode_string);
|
2017-09-12 16:32:37 +00:00
|
|
|
tcx.sess.warn(&message);
|
2015-11-02 13:46:39 +00:00
|
|
|
}
|
|
|
|
|
2017-10-25 15:05:19 +00:00
|
|
|
MonoItemCollectionMode::Lazy
|
2015-11-02 13:46:39 +00:00
|
|
|
}
|
|
|
|
}
|
2017-12-21 16:49:24 +00:00
|
|
|
None => {
|
|
|
|
if tcx.sess.opts.cg.link_dead_code {
|
|
|
|
MonoItemCollectionMode::Eager
|
|
|
|
} else {
|
|
|
|
MonoItemCollectionMode::Lazy
|
|
|
|
}
|
|
|
|
}
|
2015-11-02 13:46:39 +00:00
|
|
|
};
|
|
|
|
|
2016-05-26 12:59:58 +00:00
|
|
|
let (items, inlining_map) =
|
2018-05-08 13:10:16 +00:00
|
|
|
time(tcx.sess, "monomorphization collection", || {
|
2017-10-26 08:14:21 +00:00
|
|
|
collector::collect_crate_mono_items(tcx, collection_mode)
|
2015-11-02 13:46:39 +00:00
|
|
|
});
|
|
|
|
|
2018-01-27 16:15:40 +00:00
|
|
|
tcx.sess.abort_if_errors();
|
|
|
|
|
2017-10-30 17:42:21 +00:00
|
|
|
::rustc_mir::monomorphize::assert_symbols_are_distinct(tcx, items.iter());
|
2016-05-26 12:59:58 +00:00
|
|
|
|
2017-12-15 20:03:48 +00:00
|
|
|
let strategy = if tcx.sess.opts.incremental.is_some() {
|
2016-04-21 20:45:33 +00:00
|
|
|
PartitioningStrategy::PerModule
|
|
|
|
} else {
|
2017-10-04 21:38:52 +00:00
|
|
|
PartitioningStrategy::FixedUnitCount(tcx.sess.codegen_units())
|
2016-04-21 20:45:33 +00:00
|
|
|
};
|
|
|
|
|
2017-12-03 13:21:23 +00:00
|
|
|
let codegen_units = time(tcx.sess, "codegen unit partitioning", || {
|
2017-09-12 16:32:37 +00:00
|
|
|
partitioning::partition(tcx,
|
2016-04-21 20:45:33 +00:00
|
|
|
items.iter().cloned(),
|
|
|
|
strategy,
|
2017-09-13 20:22:20 +00:00
|
|
|
&inlining_map)
|
2017-09-12 18:04:46 +00:00
|
|
|
.into_iter()
|
|
|
|
.map(Arc::new)
|
|
|
|
.collect::<Vec<_>>()
|
2016-03-24 15:40:49 +00:00
|
|
|
});
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
let mono_items: DefIdSet = items.iter().filter_map(|mono_item| {
|
|
|
|
match *mono_item {
|
2017-10-25 15:04:24 +00:00
|
|
|
MonoItem::Fn(ref instance) => Some(instance.def_id()),
|
2018-02-19 15:47:59 +00:00
|
|
|
MonoItem::Static(def_id) => Some(def_id),
|
2017-09-13 22:24:13 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}).collect();
|
2016-06-08 01:14:51 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
if tcx.sess.opts.debugging_opts.print_mono_items.is_some() {
|
2016-11-08 03:02:55 +00:00
|
|
|
let mut item_to_cgus = FxHashMap();
|
2016-03-24 15:40:49 +00:00
|
|
|
|
2016-05-06 18:27:34 +00:00
|
|
|
for cgu in &codegen_units {
|
2018-05-08 13:10:16 +00:00
|
|
|
for (&mono_item, &linkage) in cgu.items() {
|
|
|
|
item_to_cgus.entry(mono_item)
|
2016-03-24 15:40:49 +00:00
|
|
|
.or_insert(Vec::new())
|
2016-07-21 16:49:59 +00:00
|
|
|
.push((cgu.name().clone(), linkage));
|
2016-03-24 15:40:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut item_keys: Vec<_> = items
|
|
|
|
.iter()
|
|
|
|
.map(|i| {
|
2017-09-12 16:32:37 +00:00
|
|
|
let mut output = i.to_string(tcx);
|
2016-03-24 15:40:49 +00:00
|
|
|
output.push_str(" @@");
|
|
|
|
let mut empty = Vec::new();
|
2017-08-01 12:03:03 +00:00
|
|
|
let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty);
|
2016-03-24 15:40:49 +00:00
|
|
|
cgus.as_mut_slice().sort_by_key(|&(ref name, _)| name.clone());
|
|
|
|
cgus.dedup();
|
2017-07-12 15:37:58 +00:00
|
|
|
for &(ref cgu_name, (linkage, _)) in cgus.iter() {
|
2016-03-24 15:40:49 +00:00
|
|
|
output.push_str(" ");
|
2018-04-11 21:02:41 +00:00
|
|
|
output.push_str(&cgu_name.as_str());
|
2016-03-24 15:40:49 +00:00
|
|
|
|
|
|
|
let linkage_abbrev = match linkage {
|
2017-09-12 18:04:46 +00:00
|
|
|
Linkage::External => "External",
|
|
|
|
Linkage::AvailableExternally => "Available",
|
|
|
|
Linkage::LinkOnceAny => "OnceAny",
|
|
|
|
Linkage::LinkOnceODR => "OnceODR",
|
|
|
|
Linkage::WeakAny => "WeakAny",
|
|
|
|
Linkage::WeakODR => "WeakODR",
|
|
|
|
Linkage::Appending => "Appending",
|
|
|
|
Linkage::Internal => "Internal",
|
|
|
|
Linkage::Private => "Private",
|
|
|
|
Linkage::ExternalWeak => "ExternalWeak",
|
|
|
|
Linkage::Common => "Common",
|
2016-03-24 15:40:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
output.push_str("[");
|
|
|
|
output.push_str(linkage_abbrev);
|
|
|
|
output.push_str("]");
|
|
|
|
}
|
|
|
|
output
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
2015-11-02 13:46:39 +00:00
|
|
|
item_keys.sort();
|
|
|
|
|
|
|
|
for item in item_keys {
|
2018-05-08 13:10:16 +00:00
|
|
|
println!("MONO_ITEM {}", item);
|
2015-11-02 13:46:39 +00:00
|
|
|
}
|
|
|
|
}
|
2016-05-06 18:27:34 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
(Arc::new(mono_items), Arc::new(codegen_units))
|
2016-05-26 12:59:58 +00:00
|
|
|
}
|
2017-08-28 22:55:32 +00:00
|
|
|
|
|
|
|
impl CrateInfo {
|
2017-09-13 20:22:20 +00:00
|
|
|
pub fn new(tcx: TyCtxt) -> CrateInfo {
|
2017-08-28 22:55:32 +00:00
|
|
|
let mut info = CrateInfo {
|
|
|
|
panic_runtime: None,
|
|
|
|
compiler_builtins: None,
|
|
|
|
profiler_runtime: None,
|
|
|
|
sanitizer_runtime: None,
|
|
|
|
is_no_builtins: FxHashSet(),
|
2017-08-29 00:06:03 +00:00
|
|
|
native_libraries: FxHashMap(),
|
2017-08-30 21:48:57 +00:00
|
|
|
used_libraries: tcx.native_libraries(LOCAL_CRATE),
|
|
|
|
link_args: tcx.link_args(LOCAL_CRATE),
|
2017-08-31 15:07:39 +00:00
|
|
|
crate_name: FxHashMap(),
|
2017-08-31 19:08:29 +00:00
|
|
|
used_crates_dynamic: cstore::used_crates(tcx, LinkagePreference::RequireDynamic),
|
|
|
|
used_crates_static: cstore::used_crates(tcx, LinkagePreference::RequireStatic),
|
|
|
|
used_crate_source: FxHashMap(),
|
2018-02-10 22:28:17 +00:00
|
|
|
wasm_imports: FxHashMap(),
|
2018-03-23 21:33:22 +00:00
|
|
|
lang_item_to_crate: FxHashMap(),
|
|
|
|
missing_lang_items: FxHashMap(),
|
2017-08-28 22:55:32 +00:00
|
|
|
};
|
2018-03-23 21:33:22 +00:00
|
|
|
let lang_items = tcx.lang_items();
|
2017-08-28 22:55:32 +00:00
|
|
|
|
2018-02-10 22:28:17 +00:00
|
|
|
let load_wasm_items = tcx.sess.crate_types.borrow()
|
2018-03-09 17:26:15 +00:00
|
|
|
.iter()
|
2018-07-26 17:13:11 +00:00
|
|
|
.any(|c| *c != config::CrateType::Rlib) &&
|
2018-06-01 17:20:00 +00:00
|
|
|
tcx.sess.opts.target_triple.triple() == "wasm32-unknown-unknown";
|
2018-03-09 17:26:15 +00:00
|
|
|
|
2018-02-10 22:28:17 +00:00
|
|
|
if load_wasm_items {
|
|
|
|
info.load_wasm_imports(tcx, LOCAL_CRATE);
|
2018-03-09 17:26:15 +00:00
|
|
|
}
|
|
|
|
|
2017-09-07 15:13:41 +00:00
|
|
|
for &cnum in tcx.crates().iter() {
|
2017-08-29 00:06:03 +00:00
|
|
|
info.native_libraries.insert(cnum, tcx.native_libraries(cnum));
|
2017-08-31 15:07:39 +00:00
|
|
|
info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string());
|
2017-08-31 19:08:29 +00:00
|
|
|
info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum));
|
2017-08-28 22:55:32 +00:00
|
|
|
if tcx.is_panic_runtime(cnum) {
|
|
|
|
info.panic_runtime = Some(cnum);
|
|
|
|
}
|
|
|
|
if tcx.is_compiler_builtins(cnum) {
|
|
|
|
info.compiler_builtins = Some(cnum);
|
|
|
|
}
|
|
|
|
if tcx.is_profiler_runtime(cnum) {
|
|
|
|
info.profiler_runtime = Some(cnum);
|
|
|
|
}
|
|
|
|
if tcx.is_sanitizer_runtime(cnum) {
|
|
|
|
info.sanitizer_runtime = Some(cnum);
|
|
|
|
}
|
|
|
|
if tcx.is_no_builtins(cnum) {
|
|
|
|
info.is_no_builtins.insert(cnum);
|
|
|
|
}
|
2018-02-10 22:28:17 +00:00
|
|
|
if load_wasm_items {
|
|
|
|
info.load_wasm_imports(tcx, cnum);
|
2018-03-09 17:26:15 +00:00
|
|
|
}
|
2018-03-23 21:33:22 +00:00
|
|
|
let missing = tcx.missing_lang_items(cnum);
|
|
|
|
for &item in missing.iter() {
|
|
|
|
if let Ok(id) = lang_items.require(item) {
|
|
|
|
info.lang_item_to_crate.insert(item, id.krate);
|
|
|
|
}
|
|
|
|
}
|
2018-04-04 23:54:30 +00:00
|
|
|
|
|
|
|
// No need to look for lang items that are whitelisted and don't
|
|
|
|
// actually need to exist.
|
|
|
|
let missing = missing.iter()
|
|
|
|
.cloned()
|
|
|
|
.filter(|&l| !weak_lang_items::whitelisted(tcx, l))
|
|
|
|
.collect();
|
2018-03-23 21:33:22 +00:00
|
|
|
info.missing_lang_items.insert(cnum, missing);
|
2017-08-28 22:55:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return info
|
|
|
|
}
|
2018-02-10 22:28:17 +00:00
|
|
|
|
|
|
|
fn load_wasm_imports(&mut self, tcx: TyCtxt, cnum: CrateNum) {
|
|
|
|
for (&id, module) in tcx.wasm_import_module_map(cnum).iter() {
|
|
|
|
let instance = Instance::mono(tcx, id);
|
|
|
|
let import_name = tcx.symbol_name(instance);
|
|
|
|
self.wasm_imports.insert(import_name.to_string(), module.clone());
|
|
|
|
}
|
|
|
|
}
|
2017-08-28 22:55:32 +00:00
|
|
|
}
|
2017-09-12 18:04:46 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
fn is_codegened_item(tcx: TyCtxt, id: DefId) -> bool {
|
|
|
|
let (all_mono_items, _) =
|
|
|
|
tcx.collect_and_partition_mono_items(LOCAL_CRATE);
|
|
|
|
all_mono_items.contains(&id)
|
2017-09-13 22:24:13 +00:00
|
|
|
}
|
|
|
|
|
2017-09-14 03:26:39 +00:00
|
|
|
fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
|
|
cgu: InternedString) -> Stats {
|
2017-09-28 09:58:45 +00:00
|
|
|
let cgu = tcx.codegen_unit(cgu);
|
2017-09-14 03:26:39 +00:00
|
|
|
|
|
|
|
let start_time = Instant::now();
|
2018-05-08 13:10:16 +00:00
|
|
|
let (stats, module) = module_codegen(tcx, cgu);
|
|
|
|
let time_to_codegen = start_time.elapsed();
|
2017-09-14 03:26:39 +00:00
|
|
|
|
|
|
|
// We assume that the cost to run LLVM on a CGU is proportional to
|
2018-05-08 13:10:16 +00:00
|
|
|
// the time we needed for codegenning it.
|
|
|
|
let cost = time_to_codegen.as_secs() * 1_000_000_000 +
|
|
|
|
time_to_codegen.subsec_nanos() as u64;
|
2017-09-14 03:26:39 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
write::submit_codegened_module_to_llvm(tcx,
|
2017-09-14 03:26:39 +00:00
|
|
|
module,
|
|
|
|
cost);
|
|
|
|
return stats;
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
fn module_codegen<'a, 'tcx>(
|
2017-09-18 10:14:52 +00:00
|
|
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
|
|
cgu: Arc<CodegenUnit<'tcx>>)
|
2018-05-08 13:10:16 +00:00
|
|
|
-> (Stats, ModuleCodegen)
|
2017-09-14 03:26:39 +00:00
|
|
|
{
|
|
|
|
let cgu_name = cgu.name().to_string();
|
|
|
|
|
2018-07-16 06:58:29 +00:00
|
|
|
// Append ".rs" to LLVM module identifier.
|
|
|
|
//
|
|
|
|
// LLVM code generator emits a ".file filename" directive
|
|
|
|
// for ELF backends. Value of the "filename" is set as the
|
|
|
|
// LLVM module identifier. Due to a LLVM MC bug[1], LLVM
|
|
|
|
// crashes if the module identifier is same as other symbols
|
|
|
|
// such as a function name in the module.
|
|
|
|
// 1. http://llvm.org/bugs/show_bug.cgi?id=11479
|
|
|
|
let llmod_id = format!("{}-{}.rs",
|
|
|
|
cgu.name(),
|
|
|
|
tcx.crate_disambiguator(LOCAL_CRATE)
|
|
|
|
.to_fingerprint().to_hex());
|
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
// Instantiate monomorphizations without filling out definitions yet...
|
2018-06-27 14:57:25 +00:00
|
|
|
let llvm_module = ModuleLlvm::new(tcx.sess, &llmod_id);
|
|
|
|
let stats = {
|
|
|
|
let cx = CodegenCx::new(tcx, cgu, &llvm_module);
|
2018-05-08 13:10:16 +00:00
|
|
|
let mono_items = cx.codegen_unit
|
2018-01-05 05:04:08 +00:00
|
|
|
.items_in_deterministic_order(cx.tcx);
|
2018-05-08 13:10:16 +00:00
|
|
|
for &(mono_item, (linkage, visibility)) in &mono_items {
|
|
|
|
mono_item.predefine(&cx, linkage, visibility);
|
2017-09-14 03:26:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ... and now that we have everything pre-defined, fill out those definitions.
|
2018-05-08 13:10:16 +00:00
|
|
|
for &(mono_item, _) in &mono_items {
|
|
|
|
mono_item.define(&cx);
|
2017-09-14 03:26:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If this codegen unit contains the main function, also create the
|
|
|
|
// wrapper here
|
2018-01-05 05:04:08 +00:00
|
|
|
maybe_create_entry_wrapper(&cx);
|
2017-09-14 03:26:39 +00:00
|
|
|
|
|
|
|
// Run replace-all-uses-with for statics that need it
|
2018-01-05 05:04:08 +00:00
|
|
|
for &(old_g, new_g) in cx.statics_to_rauw.borrow().iter() {
|
2017-09-14 03:26:39 +00:00
|
|
|
unsafe {
|
2018-07-02 14:52:53 +00:00
|
|
|
let bitcast = llvm::LLVMConstPointerCast(new_g, val_ty(old_g));
|
2017-09-14 03:26:39 +00:00
|
|
|
llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
|
|
|
|
llvm::LLVMDeleteGlobal(old_g);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the llvm.used variable
|
|
|
|
// This variable has type [N x i8*] and is stored in the llvm.metadata section
|
2018-01-05 05:04:08 +00:00
|
|
|
if !cx.used_statics.borrow().is_empty() {
|
2017-09-14 03:26:39 +00:00
|
|
|
let name = CString::new("llvm.used").unwrap();
|
|
|
|
let section = CString::new("llvm.metadata").unwrap();
|
2018-01-05 05:04:08 +00:00
|
|
|
let array = C_array(Type::i8(&cx).ptr_to(), &*cx.used_statics.borrow());
|
2017-09-14 03:26:39 +00:00
|
|
|
|
|
|
|
unsafe {
|
2018-01-05 05:04:08 +00:00
|
|
|
let g = llvm::LLVMAddGlobal(cx.llmod,
|
2018-07-02 14:52:53 +00:00
|
|
|
val_ty(array),
|
2017-09-14 03:26:39 +00:00
|
|
|
name.as_ptr());
|
|
|
|
llvm::LLVMSetInitializer(g, array);
|
|
|
|
llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
|
|
|
|
llvm::LLVMSetSection(g, section.as_ptr());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finalize debuginfo
|
2018-07-26 17:41:10 +00:00
|
|
|
if cx.sess().opts.debuginfo != DebugInfo::None {
|
2018-01-05 05:04:08 +00:00
|
|
|
debuginfo::finalize(&cx);
|
2017-09-14 03:26:39 +00:00
|
|
|
}
|
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
cx.stats.into_inner()
|
2017-09-14 03:26:39 +00:00
|
|
|
};
|
|
|
|
|
2018-06-27 14:57:25 +00:00
|
|
|
(stats, ModuleCodegen {
|
|
|
|
name: cgu_name,
|
|
|
|
source: ModuleSource::Codegened(llvm_module),
|
|
|
|
kind: ModuleKind::Regular,
|
|
|
|
llmod_id,
|
|
|
|
})
|
2017-09-14 03:26:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-12 16:00:18 +00:00
|
|
|
pub fn provide(providers: &mut Providers) {
|
2018-05-08 13:10:16 +00:00
|
|
|
providers.collect_and_partition_mono_items =
|
|
|
|
collect_and_partition_mono_items;
|
2017-09-13 22:24:13 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
providers.is_codegened_item = is_codegened_item;
|
2017-09-14 03:26:39 +00:00
|
|
|
|
|
|
|
providers.codegen_unit = |tcx, name| {
|
2018-05-08 13:10:16 +00:00
|
|
|
let (_, all) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
|
2017-09-14 03:26:39 +00:00
|
|
|
all.iter()
|
|
|
|
.find(|cgu| *cgu.name() == name)
|
|
|
|
.cloned()
|
2018-07-23 12:47:13 +00:00
|
|
|
.unwrap_or_else(|| panic!("failed to find cgu with name {:?}", name))
|
2017-09-14 03:26:39 +00:00
|
|
|
};
|
|
|
|
providers.compile_codegen_unit = compile_codegen_unit;
|
2018-02-10 22:28:17 +00:00
|
|
|
|
|
|
|
provide_extern(providers);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn provide_extern(providers: &mut Providers) {
|
|
|
|
providers.dllimport_foreign_items = |tcx, krate| {
|
|
|
|
let module_map = tcx.foreign_modules(krate);
|
|
|
|
let module_map = module_map.iter()
|
|
|
|
.map(|lib| (lib.def_id, lib))
|
|
|
|
.collect::<FxHashMap<_, _>>();
|
|
|
|
|
|
|
|
let dllimports = tcx.native_libraries(krate)
|
|
|
|
.iter()
|
|
|
|
.filter(|lib| {
|
|
|
|
if lib.kind != cstore::NativeLibraryKind::NativeUnknown {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
let cfg = match lib.cfg {
|
|
|
|
Some(ref cfg) => cfg,
|
|
|
|
None => return true,
|
|
|
|
};
|
|
|
|
attr::cfg_matches(cfg, &tcx.sess.parse_sess, None)
|
|
|
|
})
|
|
|
|
.filter_map(|lib| lib.foreign_module)
|
|
|
|
.map(|id| &module_map[&id])
|
|
|
|
.flat_map(|module| module.foreign_items.iter().cloned())
|
|
|
|
.collect();
|
|
|
|
Lrc::new(dllimports)
|
|
|
|
};
|
|
|
|
|
|
|
|
providers.is_dllimport_foreign_item = |tcx, def_id| {
|
|
|
|
tcx.dllimport_foreign_items(def_id.krate).contains(&def_id)
|
|
|
|
};
|
2017-09-13 22:24:13 +00:00
|
|
|
}
|
|
|
|
|
2017-09-12 18:04:46 +00:00
|
|
|
pub fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage {
|
|
|
|
match linkage {
|
|
|
|
Linkage::External => llvm::Linkage::ExternalLinkage,
|
|
|
|
Linkage::AvailableExternally => llvm::Linkage::AvailableExternallyLinkage,
|
|
|
|
Linkage::LinkOnceAny => llvm::Linkage::LinkOnceAnyLinkage,
|
|
|
|
Linkage::LinkOnceODR => llvm::Linkage::LinkOnceODRLinkage,
|
|
|
|
Linkage::WeakAny => llvm::Linkage::WeakAnyLinkage,
|
|
|
|
Linkage::WeakODR => llvm::Linkage::WeakODRLinkage,
|
|
|
|
Linkage::Appending => llvm::Linkage::AppendingLinkage,
|
|
|
|
Linkage::Internal => llvm::Linkage::InternalLinkage,
|
|
|
|
Linkage::Private => llvm::Linkage::PrivateLinkage,
|
|
|
|
Linkage::ExternalWeak => llvm::Linkage::ExternalWeakLinkage,
|
|
|
|
Linkage::Common => llvm::Linkage::CommonLinkage,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility {
|
|
|
|
match linkage {
|
|
|
|
Visibility::Default => llvm::Visibility::Default,
|
|
|
|
Visibility::Hidden => llvm::Visibility::Hidden,
|
|
|
|
Visibility::Protected => llvm::Visibility::Protected,
|
2017-09-18 10:14:52 +00:00
|
|
|
}
|
2017-09-07 14:11:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME(mw): Anything that is produced via DepGraph::with_task() must implement
|
|
|
|
// the HashStable trait. Normally DepGraph::with_task() calls are
|
|
|
|
// hidden behind queries, but CGU creation is a special case in two
|
|
|
|
// ways: (1) it's not a query and (2) CGU are output nodes, so their
|
|
|
|
// Fingerprints are not actually needed. It remains to be clarified
|
|
|
|
// how exactly this case will be handled in the red/green system but
|
|
|
|
// for now we content ourselves with providing a no-op HashStable
|
|
|
|
// implementation for CGUs.
|
|
|
|
mod temp_stable_hash_impls {
|
|
|
|
use rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher,
|
|
|
|
HashStable};
|
2018-05-08 13:10:16 +00:00
|
|
|
use ModuleCodegen;
|
2017-09-07 14:11:58 +00:00
|
|
|
|
2018-05-08 13:10:16 +00:00
|
|
|
impl<HCX> HashStable<HCX> for ModuleCodegen {
|
2017-09-07 14:11:58 +00:00
|
|
|
fn hash_stable<W: StableHasherResult>(&self,
|
|
|
|
_: &mut HCX,
|
|
|
|
_: &mut StableHasher<W>) {
|
|
|
|
// do nothing
|
|
|
|
}
|
2017-09-12 18:04:46 +00:00
|
|
|
}
|
|
|
|
}
|